lib/zstd/mem.h: replace __inline by inline
[linux-2.6-microblaze.git] / fs / nfs / nfs4state.c
index 9afd051..cad4e06 100644 (file)
@@ -624,24 +624,39 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
 /**
  * nfs4_purge_state_owners - Release all cached state owners
  * @server: nfs_server with cached state owners to release
+ * @head: resulting list of state owners
  *
  * Called at umount time.  Remaining state owners will be on
  * the LRU with ref count of zero.
+ * Note that the state owners are not freed, but are added
+ * to the list @head, which can later be used as an argument
+ * to nfs4_free_state_owners.
  */
-void nfs4_purge_state_owners(struct nfs_server *server)
+void nfs4_purge_state_owners(struct nfs_server *server, struct list_head *head)
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_state_owner *sp, *tmp;
-       LIST_HEAD(doomed);
 
        spin_lock(&clp->cl_lock);
        list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
-               list_move(&sp->so_lru, &doomed);
+               list_move(&sp->so_lru, head);
                nfs4_remove_state_owner_locked(sp);
        }
        spin_unlock(&clp->cl_lock);
+}
 
-       list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
+/**
+ * nfs4_purge_state_owners - Release all cached state owners
+ * @head: resulting list of state owners
+ *
+ * Frees a list of state owners that was generated by
+ * nfs4_purge_state_owners
+ */
+void nfs4_free_state_owners(struct list_head *head)
+{
+       struct nfs4_state_owner *sp, *tmp;
+
+       list_for_each_entry_safe(sp, tmp, head, so_lru) {
                list_del(&sp->so_lru);
                nfs4_free_state_owner(sp);
        }
@@ -1463,7 +1478,7 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
                nfs4_schedule_state_manager(clp);
 }
 
-static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
+static void nfs4_state_mark_open_context_bad(struct nfs4_state *state, int err)
 {
        struct inode *inode = state->inode;
        struct nfs_inode *nfsi = NFS_I(inode);
@@ -1474,6 +1489,8 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
                if (ctx->state != state)
                        continue;
                set_bit(NFS_CONTEXT_BAD, &ctx->flags);
+               pr_warn("NFSv4: state recovery failed for open file %pd2, "
+                               "error = %d\n", ctx->dentry, err);
        }
        rcu_read_unlock();
 }
@@ -1481,7 +1498,7 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
 static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
 {
        set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
-       nfs4_state_mark_open_context_bad(state);
+       nfs4_state_mark_open_context_bad(state, error);
 }
 
 
@@ -1512,6 +1529,7 @@ restart:
                switch (status) {
                case 0:
                        break;
+               case -ETIMEDOUT:
                case -ESTALE:
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
@@ -1605,6 +1623,7 @@ static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_st
 static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
 {
        struct nfs4_state *state;
+       unsigned int loop = 0;
        int status = 0;
 
        /* Note: we rely on the sp->so_states list being ordered 
@@ -1631,8 +1650,10 @@ restart:
 
                switch (status) {
                default:
-                       if (status >= 0)
+                       if (status >= 0) {
+                               loop = 0;
                                break;
+                       }
                        printk(KERN_ERR "NFS: %s: unhandled error %d\n", __func__, status);
                        /* Fall through */
                case -ENOENT:
@@ -1646,6 +1667,10 @@ restart:
                        break;
                case -EAGAIN:
                        ssleep(1);
+                       if (loop++ < 10) {
+                               set_bit(ops->state_flag_bit, &state->flags);
+                               break;
+                       }
                        /* Fall through */
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
@@ -1658,11 +1683,13 @@ restart:
                case -NFS4ERR_EXPIRED:
                case -NFS4ERR_NO_GRACE:
                        nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
+                       /* Fall through */
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
                case -NFS4ERR_BAD_HIGH_SLOT:
                case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+               case -ETIMEDOUT:
                        goto out_err;
                }
                nfs4_put_open_state(state);
@@ -1856,12 +1883,13 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
        struct nfs4_state_owner *sp;
        struct nfs_server *server;
        struct rb_node *pos;
+       LIST_HEAD(freeme);
        int status = 0;
 
 restart:
        rcu_read_lock();
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
-               nfs4_purge_state_owners(server);
+               nfs4_purge_state_owners(server, &freeme);
                spin_lock(&clp->cl_lock);
                for (pos = rb_first(&server->state_owners);
                     pos != NULL;
@@ -1890,6 +1918,7 @@ restart:
                spin_unlock(&clp->cl_lock);
        }
        rcu_read_unlock();
+       nfs4_free_state_owners(&freeme);
        return 0;
 }
 
@@ -1945,7 +1974,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
                return -EPERM;
        case -EACCES:
        case -NFS4ERR_DELAY:
-       case -ETIMEDOUT:
        case -EAGAIN:
                ssleep(1);
                break;
@@ -2574,7 +2602,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
                }
 
                /* Now recover expired state... */
-               if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
+               if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
                        section = "reclaim nograce";
                        status = nfs4_do_reclaim(clp,
                                clp->cl_mvops->nograce_recovery_ops);
@@ -2582,6 +2610,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
                                continue;
                        if (status < 0)
                                goto out_error;
+                       clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
                }
 
                nfs4_end_drain_session(clp);