|
@@ -29,6 +29,9 @@
|
|
|
*/
|
|
|
|
|
|
#include <linux/export.h>
|
|
|
+#include <linux/nfs_fs.h>
|
|
|
+#include "nfs4session.h"
|
|
|
+#include "internal.h"
|
|
|
#include "pnfs.h"
|
|
|
|
|
|
#define NFSDBG_FACILITY NFSDBG_PNFS
|
|
@@ -89,6 +92,74 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld,
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static struct nfs4_deviceid_node *
|
|
|
+nfs4_get_device_info(struct nfs_server *server,
|
|
|
+ const struct nfs4_deviceid *dev_id,
|
|
|
+ struct rpc_cred *cred, gfp_t gfp_flags)
|
|
|
+{
|
|
|
+ struct nfs4_deviceid_node *d = NULL;
|
|
|
+ struct pnfs_device *pdev = NULL;
|
|
|
+ struct page **pages = NULL;
|
|
|
+ u32 max_resp_sz;
|
|
|
+ int max_pages;
|
|
|
+ int rc, i;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Use the session max response size as the basis for setting
|
|
|
+ * GETDEVICEINFO's maxcount
|
|
|
+ */
|
|
|
+ max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
|
|
|
+ if (server->pnfs_curr_ld->max_deviceinfo_size &&
|
|
|
+ server->pnfs_curr_ld->max_deviceinfo_size < max_resp_sz)
|
|
|
+ max_resp_sz = server->pnfs_curr_ld->max_deviceinfo_size;
|
|
|
+ max_pages = nfs_page_array_len(0, max_resp_sz);
|
|
|
+ dprintk("%s: server %p max_resp_sz %u max_pages %d\n",
|
|
|
+ __func__, server, max_resp_sz, max_pages);
|
|
|
+
|
|
|
+ pdev = kzalloc(sizeof(*pdev), gfp_flags);
|
|
|
+ if (!pdev)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
|
|
|
+ if (!pages)
|
|
|
+ goto out_free_pdev;
|
|
|
+
|
|
|
+ for (i = 0; i < max_pages; i++) {
|
|
|
+ pages[i] = alloc_page(gfp_flags);
|
|
|
+ if (!pages[i])
|
|
|
+ goto out_free_pages;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
|
|
|
+ pdev->layout_type = server->pnfs_curr_ld->id;
|
|
|
+ pdev->pages = pages;
|
|
|
+ pdev->pgbase = 0;
|
|
|
+ pdev->pglen = max_resp_sz;
|
|
|
+ pdev->mincount = 0;
|
|
|
+ pdev->maxcount = max_resp_sz - nfs41_maxgetdevinfo_overhead;
|
|
|
+
|
|
|
+ rc = nfs4_proc_getdeviceinfo(server, pdev, cred);
|
|
|
+ dprintk("%s getdevice info returns %d\n", __func__, rc);
|
|
|
+ if (rc)
|
|
|
+ goto out_free_pages;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Found new device, need to decode it and then add it to the
|
|
|
+ * list of known devices for this mountpoint.
|
|
|
+ */
|
|
|
+ d = server->pnfs_curr_ld->alloc_deviceid_node(server, pdev,
|
|
|
+ gfp_flags);
|
|
|
+
|
|
|
+out_free_pages:
|
|
|
+ for (i = 0; i < max_pages; i++)
|
|
|
+ __free_page(pages[i]);
|
|
|
+ kfree(pages);
|
|
|
+out_free_pdev:
|
|
|
+ kfree(pdev);
|
|
|
+ dprintk("<-- %s d %p\n", __func__, d);
|
|
|
+ return d;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Lookup a deviceid in cache and get a reference count on it if found
|
|
|
*
|
|
@@ -96,14 +167,14 @@ _lookup_deviceid(const struct pnfs_layoutdriver_type *ld,
|
|
|
* @id deviceid to look up
|
|
|
*/
|
|
|
static struct nfs4_deviceid_node *
|
|
|
-_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
|
|
|
- const struct nfs_client *clp, const struct nfs4_deviceid *id,
|
|
|
- long hash)
|
|
|
+__nfs4_find_get_deviceid(struct nfs_server *server,
|
|
|
+ const struct nfs4_deviceid *id, long hash)
|
|
|
{
|
|
|
struct nfs4_deviceid_node *d;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- d = _lookup_deviceid(ld, clp, id, hash);
|
|
|
+ d = _lookup_deviceid(server->pnfs_curr_ld, server->nfs_client, id,
|
|
|
+ hash);
|
|
|
if (d != NULL)
|
|
|
atomic_inc(&d->ref);
|
|
|
rcu_read_unlock();
|
|
@@ -111,10 +182,33 @@ _find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
|
|
|
}
|
|
|
|
|
|
struct nfs4_deviceid_node *
|
|
|
-nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
|
|
|
- const struct nfs_client *clp, const struct nfs4_deviceid *id)
|
|
|
+nfs4_find_get_deviceid(struct nfs_server *server,
|
|
|
+ const struct nfs4_deviceid *id, struct rpc_cred *cred,
|
|
|
+ gfp_t gfp_mask)
|
|
|
{
|
|
|
- return _find_get_deviceid(ld, clp, id, nfs4_deviceid_hash(id));
|
|
|
+ long hash = nfs4_deviceid_hash(id);
|
|
|
+ struct nfs4_deviceid_node *d, *new;
|
|
|
+
|
|
|
+ d = __nfs4_find_get_deviceid(server, id, hash);
|
|
|
+ if (d)
|
|
|
+ return d;
|
|
|
+
|
|
|
+ new = nfs4_get_device_info(server, id, cred, gfp_mask);
|
|
|
+ if (!new)
|
|
|
+ return new;
|
|
|
+
|
|
|
+ spin_lock(&nfs4_deviceid_lock);
|
|
|
+ d = __nfs4_find_get_deviceid(server, id, hash);
|
|
|
+ if (d) {
|
|
|
+ spin_unlock(&nfs4_deviceid_lock);
|
|
|
+ server->pnfs_curr_ld->free_deviceid_node(new);
|
|
|
+ return d;
|
|
|
+ }
|
|
|
+ hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]);
|
|
|
+ atomic_inc(&new->ref);
|
|
|
+ spin_unlock(&nfs4_deviceid_lock);
|
|
|
+
|
|
|
+ return new;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
|
|
|
|
|
@@ -151,54 +245,19 @@ nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
|
|
|
EXPORT_SYMBOL_GPL(nfs4_delete_deviceid);
|
|
|
|
|
|
void
|
|
|
-nfs4_init_deviceid_node(struct nfs4_deviceid_node *d,
|
|
|
- const struct pnfs_layoutdriver_type *ld,
|
|
|
- const struct nfs_client *nfs_client,
|
|
|
+nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, struct nfs_server *server,
|
|
|
const struct nfs4_deviceid *id)
|
|
|
{
|
|
|
INIT_HLIST_NODE(&d->node);
|
|
|
INIT_HLIST_NODE(&d->tmpnode);
|
|
|
- d->ld = ld;
|
|
|
- d->nfs_client = nfs_client;
|
|
|
+ d->ld = server->pnfs_curr_ld;
|
|
|
+ d->nfs_client = server->nfs_client;
|
|
|
d->flags = 0;
|
|
|
d->deviceid = *id;
|
|
|
atomic_set(&d->ref, 1);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node);
|
|
|
|
|
|
-/*
|
|
|
- * Uniquely initialize and insert a deviceid node into cache
|
|
|
- *
|
|
|
- * @new new deviceid node
|
|
|
- * Note that the caller must set up the following members:
|
|
|
- * new->ld
|
|
|
- * new->nfs_client
|
|
|
- * new->deviceid
|
|
|
- *
|
|
|
- * @ret the inserted node, if none found, otherwise, the found entry.
|
|
|
- */
|
|
|
-struct nfs4_deviceid_node *
|
|
|
-nfs4_insert_deviceid_node(struct nfs4_deviceid_node *new)
|
|
|
-{
|
|
|
- struct nfs4_deviceid_node *d;
|
|
|
- long hash;
|
|
|
-
|
|
|
- spin_lock(&nfs4_deviceid_lock);
|
|
|
- hash = nfs4_deviceid_hash(&new->deviceid);
|
|
|
- d = _find_get_deviceid(new->ld, new->nfs_client, &new->deviceid, hash);
|
|
|
- if (d) {
|
|
|
- spin_unlock(&nfs4_deviceid_lock);
|
|
|
- return d;
|
|
|
- }
|
|
|
-
|
|
|
- hlist_add_head_rcu(&new->node, &nfs4_deviceid_cache[hash]);
|
|
|
- spin_unlock(&nfs4_deviceid_lock);
|
|
|
- atomic_inc(&new->ref);
|
|
|
-
|
|
|
- return new;
|
|
|
-}
|
|
|
-EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node);
|
|
|
-
|
|
|
/*
|
|
|
* Dereference a deviceid node and delete it when its reference count drops
|
|
|
* to zero.
|