Merge branch 'fix/hda' into for-linus
[pandora-kernel.git] / fs / nfs / nfs4state.c
index e17bd44..65ca8c1 100644 (file)
@@ -114,6 +114,20 @@ struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
        return cred;
 }
 
+#if defined(CONFIG_NFS_V4_1)
+
+struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
+{
+       struct rpc_cred *cred;
+
+       spin_lock(&clp->cl_lock);
+       cred = nfs4_get_machine_cred_locked(clp);
+       spin_unlock(&clp->cl_lock);
+       return cred;
+}
+
+#endif /* CONFIG_NFS_V4_1 */
+
 struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
 {
        struct nfs4_state_owner *sp;
@@ -539,6 +553,7 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
        INIT_LIST_HEAD(&lsp->ls_sequence.list);
        lsp->ls_seqid.sequence = &lsp->ls_sequence;
        atomic_set(&lsp->ls_count, 1);
+       lsp->ls_state = state;
        lsp->ls_owner = fl_owner;
        spin_lock(&clp->cl_lock);
        nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64);
@@ -573,7 +588,6 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
                if (lsp != NULL)
                        break;
                if (new != NULL) {
-                       new->ls_state = state;
                        list_add(&new->ls_locks, &state->lock_states);
                        set_bit(LK_STATE_IN_USE, &state->flags);
                        lsp = new;
@@ -728,12 +742,14 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 
 void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
 {
-       if (status == -NFS4ERR_BAD_SEQID) {
-               struct nfs4_state_owner *sp = container_of(seqid->sequence,
-                               struct nfs4_state_owner, so_seqid);
+       struct nfs4_state_owner *sp = container_of(seqid->sequence,
+                                       struct nfs4_state_owner, so_seqid);
+       struct nfs_server *server = sp->so_server;
+
+       if (status == -NFS4ERR_BAD_SEQID)
                nfs4_drop_state_owner(sp);
-       }
-       nfs_increment_seqid(status, seqid);
+       if (!nfs4_has_session(server->nfs_client))
+               nfs_increment_seqid(status, seqid);
 }
 
 /*
@@ -837,32 +853,45 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
        struct file_lock *fl;
        int status = 0;
 
+       if (inode->i_flock == NULL)
+               return 0;
+
+       /* Guard against delegation returns and new lock/unlock calls */
        down_write(&nfsi->rwsem);
+       /* Protect inode->i_flock using the BKL */
+       lock_kernel();
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
                        continue;
                if (nfs_file_open_context(fl->fl_file)->state != state)
                        continue;
+               unlock_kernel();
                status = ops->recover_lock(state, fl);
-               if (status >= 0)
-                       continue;
                switch (status) {
+                       case 0:
+                               break;
+                       case -ESTALE:
+                       case -NFS4ERR_ADMIN_REVOKED:
+                       case -NFS4ERR_STALE_STATEID:
+                       case -NFS4ERR_BAD_STATEID:
+                       case -NFS4ERR_EXPIRED:
+                       case -NFS4ERR_NO_GRACE:
+                       case -NFS4ERR_STALE_CLIENTID:
+                               goto out;
                        default:
                                printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
                                                __func__, status);
-                       case -NFS4ERR_EXPIRED:
-                       case -NFS4ERR_NO_GRACE:
+                       case -ENOMEM:
+                       case -NFS4ERR_DENIED:
                        case -NFS4ERR_RECLAIM_BAD:
                        case -NFS4ERR_RECLAIM_CONFLICT:
                                /* kill_proc(fl->fl_pid, SIGLOST, 1); */
-                               break;
-                       case -NFS4ERR_STALE_CLIENTID:
-                               goto out_err;
+                               status = 0;
                }
+               lock_kernel();
        }
-       up_write(&nfsi->rwsem);
-       return 0;
-out_err:
+       unlock_kernel();
+out:
        up_write(&nfsi->rwsem);
        return status;
 }
@@ -908,6 +937,7 @@ restart:
                                printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
                                                __func__, status);
                        case -ENOENT:
+                       case -ENOMEM:
                        case -ESTALE:
                                /*
                                 * Open state on this file cannot be recovered
@@ -918,6 +948,9 @@ restart:
                                /* Mark the file as being 'closed' */
                                state->state = 0;
                                break;
+                       case -NFS4ERR_ADMIN_REVOKED:
+                       case -NFS4ERR_STALE_STATEID:
+                       case -NFS4ERR_BAD_STATEID:
                        case -NFS4ERR_RECLAIM_BAD:
                        case -NFS4ERR_RECLAIM_CONFLICT:
                                nfs4_state_mark_reclaim_nograce(sp->so_client, state);
@@ -1102,7 +1135,7 @@ static int nfs4_reclaim_lease(struct nfs_client *clp)
                nfs4_reboot_recovery_ops[clp->cl_minorversion];
        int status = -ENOENT;
 
-       cred = nfs4_get_setclientid_cred(clp);
+       cred = ops->get_clid_cred(clp);
        if (cred != NULL) {
                status = ops->establish_clid(clp, cred);
                put_rpccred(cred);
@@ -1169,6 +1202,27 @@ static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
 static int nfs4_initialize_session(struct nfs_client *clp) { return 0; }
 #endif /* CONFIG_NFS_V4_1 */
 
+/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
+ * on EXCHANGE_ID for v4.1
+ */
+static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
+{
+       if (nfs4_has_session(clp)) {
+               switch (status) {
+               case -NFS4ERR_DELAY:
+               case -NFS4ERR_CLID_INUSE:
+               case -EAGAIN:
+                       break;
+
+               case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
+                                        * in nfs4_exchange_id */
+               default:
+                       return;
+               }
+       }
+       set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+}
+
 static void nfs4_state_manager(struct nfs_client *clp)
 {
        int status = 0;
@@ -1179,7 +1233,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
                        /* We're going to have to re-establish a clientid */
                        status = nfs4_reclaim_lease(clp);
                        if (status) {
-                               set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
+                               nfs4_set_lease_expired(clp, status);
                                if (status == -EAGAIN)
                                        continue;
                                if (clp->cl_cons_state ==