Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs...
[pandora-kernel.git] / fs / nfs / pnfs_dev.c
index f0f8e1e..6fda522 100644 (file)
@@ -100,8 +100,8 @@ _find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 
        rcu_read_lock();
        d = _lookup_deviceid(ld, clp, id, hash);
-       if (d && !atomic_inc_not_zero(&d->ref))
-               d = NULL;
+       if (d != NULL)
+               atomic_inc(&d->ref);
        rcu_read_unlock();
        return d;
 }
@@ -115,15 +115,15 @@ nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *ld,
 EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid);
 
 /*
- * Unhash and put deviceid
+ * Remove a deviceid from cache
  *
  * @clp nfs_client associated with deviceid
  * @id the deviceid to unhash
  *
  * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise.
  */
-struct nfs4_deviceid_node *
-nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
+void
+nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
                         const struct nfs_client *clp, const struct nfs4_deviceid *id)
 {
        struct nfs4_deviceid_node *d;
@@ -134,7 +134,7 @@ nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
        rcu_read_unlock();
        if (!d) {
                spin_unlock(&nfs4_deviceid_lock);
-               return NULL;
+               return;
        }
        hlist_del_init_rcu(&d->node);
        spin_unlock(&nfs4_deviceid_lock);
@@ -142,28 +142,7 @@ nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld,
 
        /* balance the initial ref set in pnfs_insert_deviceid */
        if (atomic_dec_and_test(&d->ref))
-               return d;
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(nfs4_unhash_put_deviceid);
-
-/*
- * Delete a deviceid from cache
- *
- * @clp struct nfs_client qualifying the deviceid
- * @id deviceid to delete
- */
-void
-nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
-                    const struct nfs_client *clp, const struct nfs4_deviceid *id)
-{
-       struct nfs4_deviceid_node *d;
-
-       d = nfs4_unhash_put_deviceid(ld, clp, id);
-       if (!d)
-               return;
-       d->ld->free_deviceid_node(d);
+               d->ld->free_deviceid_node(d);
 }
 EXPORT_SYMBOL_GPL(nfs4_delete_deviceid);
 
@@ -177,6 +156,7 @@ nfs4_init_deviceid_node(struct nfs4_deviceid_node *d,
        INIT_HLIST_NODE(&d->tmpnode);
        d->ld = ld;
        d->nfs_client = nfs_client;
+       d->flags = 0;
        d->deviceid = *id;
        atomic_set(&d->ref, 1);
 }
@@ -221,16 +201,15 @@ EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node);
  *
  * @d deviceid node to put
  *
- * @ret true iff the node was deleted
+ * return true iff the node was deleted
+ * Note that since the test for d->ref == 0 is sufficient to establish
+ * that the node is no longer hashed in the global device id cache.
  */
 bool
 nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
 {
-       if (!atomic_dec_and_lock(&d->ref, &nfs4_deviceid_lock))
+       if (!atomic_dec_and_test(&d->ref))
                return false;
-       hlist_del_init_rcu(&d->node);
-       spin_unlock(&nfs4_deviceid_lock);
-       synchronize_rcu();
        d->ld->free_deviceid_node(d);
        return true;
 }
@@ -275,3 +254,22 @@ nfs4_deviceid_purge_client(const struct nfs_client *clp)
        for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++)
                _deviceid_purge_client(clp, h);
 }
+
+/*
+ * Stop use of all deviceids associated with an nfs_client
+ */
+void
+nfs4_deviceid_mark_client_invalid(struct nfs_client *clp)
+{
+       struct nfs4_deviceid_node *d;
+       struct hlist_node *n;
+       int i;
+
+       rcu_read_lock();
+       for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){
+               hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[i], node)
+                       if (d->nfs_client == clp)
+                               set_bit(NFS_DEVICEID_INVALID, &d->flags);
+       }
+       rcu_read_unlock();
+}