]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/nfs4proc.c
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / fs / nfs / nfs4proc.c
index 15052b81df4245e4f797adb0d0b2e523338b23cc..2da6a698b8f7719c14eefec65e6148a48d030bb3 100644 (file)
@@ -539,7 +539,7 @@ static int nfs40_sequence_done(struct rpc_task *task,
        struct nfs4_slot *slot = res->sr_slot;
        struct nfs4_slot_table *tbl;
 
-       if (!RPC_WAS_SENT(task))
+       if (slot == NULL)
                goto out;
 
        tbl = slot->table;
@@ -559,15 +559,10 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
 {
        struct nfs4_session *session;
        struct nfs4_slot_table *tbl;
+       struct nfs4_slot *slot = res->sr_slot;
        bool send_new_highest_used_slotid = false;
 
-       if (!res->sr_slot) {
-               /* just wake up the next guy waiting since
-                * we may have not consumed a slot after all */
-               dprintk("%s: No slot\n", __func__);
-               return;
-       }
-       tbl = res->sr_slot->table;
+       tbl = slot->table;
        session = tbl->session;
 
        spin_lock(&tbl->slot_tbl_lock);
@@ -577,11 +572,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
        if (tbl->highest_used_slotid > tbl->target_highest_slotid)
                send_new_highest_used_slotid = true;
 
-       if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
+       if (nfs41_wake_and_assign_slot(tbl, slot)) {
                send_new_highest_used_slotid = false;
                goto out_unlock;
        }
-       nfs4_free_slot(tbl, res->sr_slot);
+       nfs4_free_slot(tbl, slot);
 
        if (tbl->highest_used_slotid != NFS4_NO_SLOT)
                send_new_highest_used_slotid = false;
@@ -592,19 +587,20 @@ out_unlock:
                nfs41_server_notify_highest_slotid_update(session->clp);
 }
 
-static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
+int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
        struct nfs4_session *session;
-       struct nfs4_slot *slot;
+       struct nfs4_slot *slot = res->sr_slot;
        struct nfs_client *clp;
        bool interrupted = false;
        int ret = 1;
 
+       if (slot == NULL)
+               goto out_noaction;
        /* don't increment the sequence number if the task wasn't sent */
        if (!RPC_WAS_SENT(task))
                goto out;
 
-       slot = res->sr_slot;
        session = slot->table->session;
 
        if (slot->interrupted) {
@@ -679,6 +675,7 @@ out:
        /* The session may be reset by one of the error handlers. */
        dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
        nfs41_sequence_free_slot(res);
+out_noaction:
        return ret;
 retry_nowait:
        if (rpc_restart_call_prepare(task)) {
@@ -692,6 +689,7 @@ out_retry:
        rpc_delay(task, NFS4_POLL_RETRY_MAX);
        return 0;
 }
+EXPORT_SYMBOL_GPL(nfs41_sequence_done);
 
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
@@ -1622,15 +1620,15 @@ static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_opendata *data = calldata;
 
-       nfs40_setup_sequence(data->o_arg.server, &data->o_arg.seq_args,
-                               &data->o_res.seq_res, task);
+       nfs40_setup_sequence(data->o_arg.server, &data->c_arg.seq_args,
+                               &data->c_res.seq_res, task);
 }
 
 static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_opendata *data = calldata;
 
-       nfs40_sequence_done(task, &data->o_res.seq_res);
+       nfs40_sequence_done(task, &data->c_res.seq_res);
 
        data->rpc_status = task->tk_status;
        if (data->rpc_status == 0) {
@@ -1688,7 +1686,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
        };
        int status;
 
-       nfs4_init_sequence(&data->o_arg.seq_args, &data->o_res.seq_res, 1);
+       nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -2744,7 +2742,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                                NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
                                NFS_CAP_CTIME|NFS_CAP_MTIME|
                                NFS_CAP_SECURITY_LABEL);
-               if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
+               if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
+                               res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
                        server->caps |= NFS_CAP_ACLS;
                if (res.has_links != 0)
                        server->caps |= NFS_CAP_HARDLINKS;
@@ -4321,9 +4320,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
 
 static inline int nfs4_server_supports_acls(struct nfs_server *server)
 {
-       return (server->caps & NFS_CAP_ACLS)
-               && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
-               && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
+       return server->caps & NFS_CAP_ACLS;
 }
 
 /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
@@ -7409,9 +7406,9 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        struct nfs_server *server = NFS_SERVER(inode);
        struct pnfs_layout_hdr *lo;
        struct nfs4_state *state = NULL;
-       unsigned long timeo, giveup;
+       unsigned long timeo, now, giveup;
 
-       dprintk("--> %s\n", __func__);
+       dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
 
        if (!nfs41_sequence_done(task, &lgp->res.seq_res))
                goto out;
@@ -7419,12 +7416,38 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        switch (task->tk_status) {
        case 0:
                goto out;
+       /*
+        * NFS4ERR_LAYOUTTRYLATER is a conflict with another client
+        * (or clients) writing to the same RAID stripe
+        */
        case -NFS4ERR_LAYOUTTRYLATER:
+       /*
+        * NFS4ERR_RECALLCONFLICT is when conflict with self (must recall
+        * existing layout before getting a new one).
+        */
        case -NFS4ERR_RECALLCONFLICT:
                timeo = rpc_get_timeout(task->tk_client);
                giveup = lgp->args.timestamp + timeo;
-               if (time_after(giveup, jiffies))
-                       task->tk_status = -NFS4ERR_DELAY;
+               now = jiffies;
+               if (time_after(giveup, now)) {
+                       unsigned long delay;
+
+                       /* Delay for:
+                        * - Not less then NFS4_POLL_RETRY_MIN.
+                        * - One last time a jiffie before we give up
+                        * - exponential backoff (time_now minus start_attempt)
+                        */
+                       delay = max_t(unsigned long, NFS4_POLL_RETRY_MIN,
+                                   min((giveup - now - 1),
+                                       now - lgp->args.timestamp));
+
+                       dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n",
+                               __func__, delay);
+                       rpc_delay(task, delay);
+                       task->tk_status = 0;
+                       rpc_restart_call_prepare(task);
+                       goto out; /* Do not call nfs4_async_handle_error() */
+               }
                break;
        case -NFS4ERR_EXPIRED:
        case -NFS4ERR_BAD_STATEID:
@@ -7780,10 +7803,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
        case -NFS4ERR_BADLAYOUT:     /* no layout */
        case -NFS4ERR_GRACE:        /* loca_recalim always false */
                task->tk_status = 0;
-               break;
        case 0:
-               nfs_post_op_update_inode_force_wcc(data->args.inode,
-                                                  data->res.fattr);
                break;
        default:
                if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
@@ -7798,6 +7818,8 @@ static void nfs4_layoutcommit_release(void *calldata)
        struct nfs4_layoutcommit_data *data = calldata;
 
        pnfs_cleanup_layoutcommit(data);
+       nfs_post_op_update_inode_force_wcc(data->args.inode,
+                                          data->res.fattr);
        put_rpccred(data->cred);
        kfree(data);
 }
@@ -7920,7 +7942,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
-               case -NFS4ERR_NOTSUPP:
+               case -ENOTSUPP:
                        goto out;
                default:
                        err = nfs4_handle_exception(server, err, &exception);
@@ -7954,7 +7976,7 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
         * Fall back on "guess and check" method if
         * the server doesn't support SECINFO_NO_NAME
         */
-       if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
+       if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
                err = nfs4_find_root_sec(server, fhandle, info);
                goto out_freepage;
        }