]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nfs/nfs4proc.c
Merge remote-tracking branch 'nfsd/nfsd-next'
[karo-tx-linux.git] / fs / nfs / nfs4proc.c
index 2e679c295185204668b747a5c8f998e5c722d45d..e810ab57a5115f4e30d6f0e4aa2f9668ae616740 100644 (file)
@@ -208,6 +208,9 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
        | FATTR4_WORD1_TIME_METADATA
        | FATTR4_WORD1_TIME_MODIFY,
        FATTR4_WORD2_MDSTHRESHOLD
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+       | FATTR4_WORD2_SECURITY_LABEL
+#endif
 };
 
 static const u32 nfs4_open_noattr_bitmap[3] = {
@@ -1385,6 +1388,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
         * Protect the call to nfs4_state_set_mode_locked and
         * serialise the stateid update
         */
+       spin_lock(&state->owner->so_lock);
        write_seqlock(&state->seqlock);
        if (deleg_stateid != NULL) {
                nfs4_stateid_copy(&state->stateid, deleg_stateid);
@@ -1393,7 +1397,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
        if (open_stateid != NULL)
                nfs_set_open_stateid_locked(state, open_stateid, fmode);
        write_sequnlock(&state->seqlock);
-       spin_lock(&state->owner->so_lock);
        update_open_stateflags(state, fmode);
        spin_unlock(&state->owner->so_lock);
 }
@@ -1598,6 +1601,7 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
 
        if (!data->rpc_done) {
                state = nfs4_try_open_cached(data);
+               trace_nfs4_cached_open(data->state);
                goto out;
        }
 
@@ -2015,6 +2019,7 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        }
        return;
 unlock_no_action:
+       trace_nfs4_cached_open(data->state);
        rcu_read_unlock();
 out_no_action:
        task->tk_action = NULL;
@@ -2703,6 +2708,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
        if (status == 0 && state != NULL)
                renew_lease(server, timestamp);
+       trace_nfs4_setattr(inode, &arg.stateid, status);
        return status;
 }
 
@@ -2719,7 +2725,6 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        int err;
        do {
                err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
-               trace_nfs4_setattr(inode, err);
                switch (err) {
                case -NFS4ERR_OPENMODE:
                        if (!(sattr->ia_valid & ATTR_SIZE)) {
@@ -5038,7 +5043,6 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
 static int
 nfs4_init_nonuniform_client_string(struct nfs_client *clp)
 {
-       int result;
        size_t len;
        char *str;
 
@@ -5066,7 +5070,7 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
                return -ENOMEM;
 
        rcu_read_lock();
-       result = scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
+       scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
                        clp->cl_ipaddr,
                        rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
                        rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO));
@@ -5079,7 +5083,6 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
 static int
 nfs4_init_uniquifier_client_string(struct nfs_client *clp)
 {
-       int result;
        size_t len;
        char *str;
 
@@ -5099,7 +5102,7 @@ nfs4_init_uniquifier_client_string(struct nfs_client *clp)
        if (!str)
                return -ENOMEM;
 
-       result = scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
+       scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
                        clp->rpc_ops->version, clp->cl_minorversion,
                        nfs4_client_id_uniquifier,
                        clp->cl_rpcclient->cl_nodename);
@@ -5110,7 +5113,6 @@ nfs4_init_uniquifier_client_string(struct nfs_client *clp)
 static int
 nfs4_init_uniform_client_string(struct nfs_client *clp)
 {
-       int result;
        size_t len;
        char *str;
 
@@ -5135,7 +5137,7 @@ nfs4_init_uniform_client_string(struct nfs_client *clp)
        if (!str)
                return -ENOMEM;
 
-       result = scnprintf(str, len, "Linux NFSv%u.%u %s",
+       scnprintf(str, len, "Linux NFSv%u.%u %s",
                        clp->rpc_ops->version, clp->cl_minorversion,
                        clp->cl_rpcclient->cl_nodename);
        clp->cl_owner_id = str;
@@ -5374,6 +5376,11 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        if (data == NULL)
                return -ENOMEM;
        nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+
+       nfs4_state_protect(server->nfs_client,
+                       NFS_SP4_MACH_CRED_CLEANUP,
+                       &task_setup_data.rpc_client, &msg);
+
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        data->args.bitmask = server->cache_consistency_bitmask;
@@ -5416,7 +5423,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
        int err;
        do {
                err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
-               trace_nfs4_delegreturn(inode, err);
+               trace_nfs4_delegreturn(inode, stateid, err);
                switch (err) {
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
@@ -5926,6 +5933,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                data->cancelled = 1;
        rpc_put_task(task);
        dprintk("%s: done, ret = %d!\n", __func__, ret);
+       trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
        return ret;
 }
 
@@ -5942,7 +5950,6 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
-               trace_nfs4_lock_reclaim(request, state, F_SETLK, err);
                if (err != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, err, &exception);
@@ -5969,7 +5976,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
-               trace_nfs4_lock_expired(request, state, F_SETLK, err);
                switch (err) {
                default:
                        goto out;
@@ -6077,7 +6083,6 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
 
        do {
                err = _nfs4_proc_setlk(state, cmd, request);
-               trace_nfs4_set_lock(request, state, cmd, err);
                if (err == -NFS4ERR_DENIED)
                        err = -EAGAIN;
                err = nfs4_handle_exception(NFS_SERVER(state->inode),
@@ -6243,9 +6248,6 @@ static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
                                   const void *buf, size_t buflen,
                                   int flags)
 {
-       if (strcmp(key, "") != 0)
-               return -EINVAL;
-
        return nfs4_proc_set_acl(d_inode(dentry), buf, buflen);
 }
 
@@ -6253,32 +6255,15 @@ static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
                                   struct dentry *dentry, const char *key,
                                   void *buf, size_t buflen)
 {
-       if (strcmp(key, "") != 0)
-               return -EINVAL;
-
        return nfs4_proc_get_acl(d_inode(dentry), buf, buflen);
 }
 
-static size_t nfs4_xattr_list_nfs4_acl(const struct xattr_handler *handler,
-                                      struct dentry *dentry, char *list,
-                                      size_t list_len, const char *name,
-                                      size_t name_len)
+static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
 {
-       size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
-
-       if (!nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry))))
-               return 0;
-
-       if (list && len <= list_len)
-               memcpy(list, XATTR_NAME_NFSV4_ACL, len);
-       return len;
+       return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)));
 }
 
 #ifdef CONFIG_NFS_V4_SECURITY_LABEL
-static inline int nfs4_server_supports_labels(struct nfs_server *server)
-{
-       return server->caps & NFS_CAP_SECURITY_LABEL;
-}
 
 static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
                                     struct dentry *dentry, const char *key,
@@ -6300,29 +6285,34 @@ static int nfs4_xattr_get_nfs4_label(const struct xattr_handler *handler,
        return -EOPNOTSUPP;
 }
 
-static size_t nfs4_xattr_list_nfs4_label(const struct xattr_handler *handler,
-                                        struct dentry *dentry, char *list,
-                                        size_t list_len, const char *name,
-                                        size_t name_len)
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
 {
-       size_t len = 0;
+       int len = 0;
 
-       if (nfs_server_capable(d_inode(dentry), NFS_CAP_SECURITY_LABEL)) {
-               len = security_inode_listsecurity(d_inode(dentry), NULL, 0);
-               if (list && len <= list_len)
-                       security_inode_listsecurity(d_inode(dentry), list, len);
+       if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
+               len = security_inode_listsecurity(inode, list, list_len);
+               if (list_len && len > list_len)
+                       return -ERANGE;
        }
        return len;
 }
 
 static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
-       .list   = nfs4_xattr_list_nfs4_label,
        .get    = nfs4_xattr_get_nfs4_label,
        .set    = nfs4_xattr_set_nfs4_label,
 };
-#endif
 
+#else
+
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
+{
+       return 0;
+}
+
+#endif
 
 /*
  * nfs_fhget will use either the mounted_on_fileid or the fileid
@@ -6852,10 +6842,13 @@ static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
        },
        .allow.u.words = {
                [0] = 1 << (OP_CLOSE) |
+                     1 << (OP_OPEN_DOWNGRADE) |
                      1 << (OP_LOCKU) |
+                     1 << (OP_DELEGRETURN) |
                      1 << (OP_COMMIT),
                [1] = 1 << (OP_SECINFO - 32) |
                      1 << (OP_SECINFO_NO_NAME - 32) |
+                     1 << (OP_LAYOUTRETURN - 32) |
                      1 << (OP_TEST_STATEID - 32) |
                      1 << (OP_FREE_STATEID - 32) |
                      1 << (OP_WRITE - 32)
@@ -6920,11 +6913,19 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
                }
 
                if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
+                   test_bit(OP_OPEN_DOWNGRADE, sp->allow.u.longs) &&
+                   test_bit(OP_DELEGRETURN, sp->allow.u.longs) &&
                    test_bit(OP_LOCKU, sp->allow.u.longs)) {
                        dfprintk(MOUNT, "  cleanup mode enabled\n");
                        set_bit(NFS_SP4_MACH_CRED_CLEANUP, &clp->cl_sp4_flags);
                }
 
+               if (test_bit(OP_LAYOUTRETURN, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  pnfs cleanup mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_PNFS_CLEANUP,
+                               &clp->cl_sp4_flags);
+               }
+
                if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
                    test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
                        dfprintk(MOUNT, "  secinfo mode enabled\n");
@@ -7753,6 +7754,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
        struct nfs4_layoutget *lgp = calldata;
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
        struct nfs4_session *session = nfs4_get_session(server);
+       int ret;
 
        dprintk("--> %s\n", __func__);
        /* Note the is a race here, where a CB_LAYOUTRECALL can come in
@@ -7763,12 +7765,12 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
        if (nfs41_setup_sequence(session, &lgp->args.seq_args,
                                &lgp->res.seq_res, task))
                return;
-       if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
+       ret = pnfs_choose_layoutget_stateid(&lgp->args.stateid,
                                          NFS_I(lgp->args.inode)->layout,
                                          &lgp->args.range,
-                                         lgp->args.ctx->state)) {
-               rpc_exit(task, NFS4_OK);
-       }
+                                         lgp->args.ctx->state);
+       if (ret < 0)
+               rpc_exit(task, ret);
 }
 
 static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
@@ -7788,6 +7790,15 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        switch (task->tk_status) {
        case 0:
                goto out;
+
+       /*
+        * NFS4ERR_LAYOUTUNAVAILABLE means we are not supposed to use pnfs
+        * on the file. set tk_status to -ENODATA to tell upper layer to
+        * retry go inband.
+        */
+       case -NFS4ERR_LAYOUTUNAVAILABLE:
+               task->tk_status = -ENODATA;
+               goto out;
        /*
         * NFS4ERR_BADLAYOUT means the MDS cannot return a layout of
         * length lgp->args.minlength != 0 (see RFC5661 section 18.43.3).
@@ -7856,7 +7867,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
                        spin_unlock(&inode->i_lock);
                goto out_restart;
        }
-       if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN)
+       if (nfs4_async_handle_error(task, server, state, &lgp->timeout) == -EAGAIN)
                goto out_restart;
 out:
        dprintk("<-- %s\n", __func__);
@@ -7984,6 +7995,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        trace_nfs4_layoutget(lgp->args.ctx,
                        &lgp->args.range,
                        &lgp->res.range,
+                       &lgp->res.stateid,
                        status);
        /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
        if (status == 0 && lgp->res.layoutp->len)
@@ -8040,11 +8052,11 @@ static void nfs4_layoutreturn_release(void *calldata)
 
        dprintk("--> %s\n", __func__);
        spin_lock(&lo->plh_inode->i_lock);
+       pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
+       pnfs_mark_layout_returned_if_empty(lo);
        if (lrp->res.lrs_present)
                pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
-       pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
        pnfs_clear_layoutreturn_waitbit(lo);
-       lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
        pnfs_free_lseg_list(&freeme);
        pnfs_put_layout_hdr(lrp->args.layout);
@@ -8076,6 +8088,10 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
        };
        int status = 0;
 
+       nfs4_state_protect(NFS_SERVER(lrp->args.inode)->nfs_client,
+                       NFS_SP4_MACH_CRED_PNFS_CLEANUP,
+                       &task_setup_data.rpc_client, &msg);
+
        dprintk("--> %s\n", __func__);
        if (!sync) {
                lrp->inode = nfs_igrab_and_active(lrp->args.inode);
@@ -8091,7 +8107,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
                return PTR_ERR(task);
        if (sync)
                status = task->tk_status;
-       trace_nfs4_layoutreturn(lrp->args.inode, status);
+       trace_nfs4_layoutreturn(lrp->args.inode, &lrp->args.stateid, status);
        dprintk("<-- %s status=%d\n", __func__, status);
        rpc_put_task(task);
        return status;
@@ -8239,7 +8255,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                return PTR_ERR(task);
        if (sync)
                status = task->tk_status;
-       trace_nfs4_layoutcommit(data->args.inode, status);
+       trace_nfs4_layoutcommit(data->args.inode, &data->args.stateid, status);
        dprintk("%s: status %d\n", __func__, status);
        rpc_put_task(task);
        return status;
@@ -8739,6 +8755,24 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 #endif
 };
 
+ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+       ssize_t error, error2;
+
+       error = generic_listxattr(dentry, list, size);
+       if (error < 0)
+               return error;
+       if (list) {
+               list += error;
+               size -= error;
+       }
+
+       error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
+       if (error2 < 0)
+               return error2;
+       return error + error2;
+}
+
 static const struct inode_operations nfs4_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
@@ -8755,7 +8789,7 @@ static const struct inode_operations nfs4_dir_inode_operations = {
        .setattr        = nfs_setattr,
        .getxattr       = generic_getxattr,
        .setxattr       = generic_setxattr,
-       .listxattr      = generic_listxattr,
+       .listxattr      = nfs4_listxattr,
        .removexattr    = generic_removexattr,
 };
 
@@ -8765,7 +8799,7 @@ static const struct inode_operations nfs4_file_inode_operations = {
        .setattr        = nfs_setattr,
        .getxattr       = generic_getxattr,
        .setxattr       = generic_setxattr,
-       .listxattr      = generic_listxattr,
+       .listxattr      = nfs4_listxattr,
        .removexattr    = generic_removexattr,
 };
 
@@ -8824,7 +8858,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
 };
 
 static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
-       .prefix = XATTR_NAME_NFSV4_ACL,
+       .name   = XATTR_NAME_NFSV4_ACL,
        .list   = nfs4_xattr_list_nfs4_acl,
        .get    = nfs4_xattr_get_nfs4_acl,
        .set    = nfs4_xattr_set_nfs4_acl,