]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/nfs/nfs4proc.c
Merge tag 'usb-5.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[linux.git] / fs / nfs / nfs4proc.c
index 76d37161409a518112fbd5152cf726385c1770b9..69b7ab7a58157f4d7b3e7787d4d2b1dc9750ff7d 100644 (file)
@@ -1097,11 +1097,12 @@ static int nfs4_call_sync_custom(struct rpc_task_setup *task_setup)
        return ret;
 }
 
-static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
-                                  struct nfs_server *server,
-                                  struct rpc_message *msg,
-                                  struct nfs4_sequence_args *args,
-                                  struct nfs4_sequence_res *res)
+static int nfs4_do_call_sync(struct rpc_clnt *clnt,
+                            struct nfs_server *server,
+                            struct rpc_message *msg,
+                            struct nfs4_sequence_args *args,
+                            struct nfs4_sequence_res *res,
+                            unsigned short task_flags)
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_call_sync_data data = {
@@ -1113,12 +1114,23 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .rpc_client = clnt,
                .rpc_message = msg,
                .callback_ops = clp->cl_mvops->call_sync_ops,
-               .callback_data = &data
+               .callback_data = &data,
+               .flags = task_flags,
        };
 
        return nfs4_call_sync_custom(&task_setup);
 }
 
+static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
+                                  struct nfs_server *server,
+                                  struct rpc_message *msg,
+                                  struct nfs4_sequence_args *args,
+                                  struct nfs4_sequence_res *res)
+{
+       return nfs4_do_call_sync(clnt, server, msg, args, res, 0);
+}
+
+
 int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs_server *server,
                   struct rpc_message *msg,
@@ -2962,10 +2974,13 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
        struct dentry *dentry;
        struct nfs4_state *state;
        fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx);
+       struct inode *dir = d_inode(opendata->dir);
+       unsigned long dir_verifier;
        unsigned int seq;
        int ret;
 
        seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
+       dir_verifier = nfs_save_change_attribute(dir);
 
        ret = _nfs4_proc_open(opendata, ctx);
        if (ret != 0)
@@ -2993,8 +3008,19 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
                        dput(ctx->dentry);
                        ctx->dentry = dentry = alias;
                }
-               nfs_set_verifier(dentry,
-                               nfs_save_change_attribute(d_inode(opendata->dir)));
+       }
+
+       switch(opendata->o_arg.claim) {
+       default:
+               break;
+       case NFS4_OPEN_CLAIM_NULL:
+       case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+       case NFS4_OPEN_CLAIM_DELEGATE_PREV:
+               if (!opendata->rpc_done)
+                       break;
+               if (opendata->o_res.delegation_type != 0)
+                       dir_verifier = nfs_save_change_attribute(dir);
+               nfs_set_verifier(dentry, dir_verifier);
        }
 
        /* Parse layoutget results before we check for access */
@@ -3187,6 +3213,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
                        exception.retry = 1;
                        continue;
                }
+               if (status == -NFS4ERR_EXPIRED) {
+                       nfs4_schedule_lease_recovery(server->nfs_client);
+                       exception.retry = 1;
+                       continue;
+               }
                if (status == -EAGAIN) {
                        /* We must have found a delegation */
                        exception.retry = 1;
@@ -3239,6 +3270,8 @@ static int _nfs4_do_setattr(struct inode *inode,
                nfs_put_lock_context(l_ctx);
                if (status == -EIO)
                        return -EBADF;
+               else if (status == -EAGAIN)
+                       goto zero_stateid;
        } else {
 zero_stateid:
                nfs4_stateid_copy(&arg->stateid, &zero_stateid);
@@ -4064,11 +4097,18 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       unsigned short task_flags = 0;
+
+       /* Is this is an attribute revalidation, subject to softreval? */
+       if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
+               task_flags |= RPC_TASK_TIMEOUT;
 
        nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, label), inode);
 
        nfs_fattr_init(fattr);
-       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+       nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
+       return nfs4_do_call_sync(server->client, server, &msg,
+                       &args.seq_args, &res.seq_res, task_flags);
 }
 
 int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
@@ -4156,7 +4196,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
 }
 
 static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
-               const struct qstr *name, struct nfs_fh *fhandle,
+               struct dentry *dentry, struct nfs_fh *fhandle,
                struct nfs_fattr *fattr, struct nfs4_label *label)
 {
        struct nfs_server *server = NFS_SERVER(dir);
@@ -4164,7 +4204,7 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
        struct nfs4_lookup_arg args = {
                .bitmask = server->attr_bitmask,
                .dir_fh = NFS_FH(dir),
-               .name = name,
+               .name = &dentry->d_name,
        };
        struct nfs4_lookup_res res = {
                .server = server,
@@ -4177,13 +4217,20 @@ static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       unsigned short task_flags = 0;
+
+       /* Is this is an attribute revalidation, subject to softreval? */
+       if (nfs_lookup_is_soft_revalidate(dentry))
+               task_flags |= RPC_TASK_TIMEOUT;
 
        args.bitmask = nfs4_bitmask(server, label);
 
        nfs_fattr_init(fattr);
 
-       dprintk("NFS call  lookup %s\n", name->name);
-       status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
+       dprintk("NFS call  lookup %pd2\n", dentry);
+       nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
+       status = nfs4_do_call_sync(clnt, server, &msg,
+                       &args.seq_args, &res.seq_res, task_flags);
        dprintk("NFS reply lookup: %d\n", status);
        return status;
 }
@@ -4197,16 +4244,17 @@ static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
 }
 
 static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
-                                  const struct qstr *name, struct nfs_fh *fhandle,
+                                  struct dentry *dentry, struct nfs_fh *fhandle,
                                   struct nfs_fattr *fattr, struct nfs4_label *label)
 {
        struct nfs4_exception exception = {
                .interruptible = true,
        };
        struct rpc_clnt *client = *clnt;
+       const struct qstr *name = &dentry->d_name;
        int err;
        do {
-               err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
+               err = _nfs4_proc_lookup(client, dir, dentry, fhandle, fattr, label);
                trace_nfs4_lookup(dir, name, err);
                switch (err) {
                case -NFS4ERR_BADNAME:
@@ -4241,14 +4289,14 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
        return err;
 }
 
-static int nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
+static int nfs4_proc_lookup(struct inode *dir, struct dentry *dentry,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr,
                            struct nfs4_label *label)
 {
        int status;
        struct rpc_clnt *client = NFS_CLIENT(dir);
 
-       status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
+       status = nfs4_proc_lookup_common(&client, dir, dentry, fhandle, fattr, label);
        if (client != NFS_CLIENT(dir)) {
                rpc_shutdown_client(client);
                nfs_fixup_secinfo_attributes(fattr);
@@ -4257,13 +4305,13 @@ static int nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
 }
 
 struct rpc_clnt *
-nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
+nfs4_proc_lookup_mountpoint(struct inode *dir, struct dentry *dentry,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
        struct rpc_clnt *client = NFS_CLIENT(dir);
        int status;
 
-       status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
+       status = nfs4_proc_lookup_common(&client, dir, dentry, fhandle, fattr, NULL);
        if (status < 0)
                return ERR_PTR(status);
        return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
@@ -5019,16 +5067,13 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str
        struct nfs4_exception exception = {
                .interruptible = true,
        };
-       unsigned long now = jiffies;
        int err;
 
        do {
                err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
                trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
                if (err == 0) {
-                       nfs4_set_lease_period(server->nfs_client,
-                                       fsinfo->lease_time * HZ,
-                                       now);
+                       nfs4_set_lease_period(server->nfs_client, fsinfo->lease_time * HZ);
                        break;
                }
                err = nfs4_handle_exception(server, err, &exception);
@@ -5291,7 +5336,7 @@ static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
        hdr->timestamp   = jiffies;
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
-       nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 1, 0);
+       nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0);
        nfs4_state_protect_write(server->nfs_client, clnt, msg, hdr);
 }
 
@@ -5582,10 +5627,9 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size
  */
 static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
 {
-       struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
+       struct page **pages;
        struct nfs_getaclargs args = {
                .fh = NFS_FH(inode),
-               .acl_pages = pages,
                .acl_len = buflen,
        };
        struct nfs_getaclres res = {
@@ -5596,11 +5640,19 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
+       unsigned int npages;
        int ret = -ENOMEM, i;
+       struct nfs_server *server = NFS_SERVER(inode);
 
-       if (npages > ARRAY_SIZE(pages))
-               return -ERANGE;
+       if (buflen == 0)
+               buflen = server->rsize;
+
+       npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
+       pages = kmalloc_array(npages, sizeof(struct page *), GFP_NOFS);
+       if (!pages)
+               return -ENOMEM;
+
+       args.acl_pages = pages;
 
        for (i = 0; i < npages; i++) {
                pages[i] = alloc_page(GFP_KERNEL);
@@ -5646,6 +5698,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                        __free_page(pages[i]);
        if (res.acl_scratch)
                __free_page(res.acl_scratch);
+       kfree(pages);
        return ret;
 }
 
@@ -6084,6 +6137,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                .callback_data = &setclientid,
                .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN,
        };
+       unsigned long now = jiffies;
        int status;
 
        /* nfs_client_id4 */
@@ -6116,6 +6170,9 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                clp->cl_acceptor = rpcauth_stringify_acceptor(setclientid.sc_cred);
                put_rpccred(setclientid.sc_cred);
        }
+
+       if (status == 0)
+               do_renew_lease(clp, now);
 out:
        trace_nfs4_setclientid(clp, status);
        dprintk("NFS reply setclientid: %d\n", status);
@@ -6859,7 +6916,7 @@ static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_
        case -NFS4ERR_STALE_STATEID:
                lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
                nfs4_schedule_lease_recovery(server->nfs_client);
-       };
+       }
 }
 
 static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
@@ -8203,6 +8260,7 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cre
        struct rpc_task *task;
        struct nfs41_exchange_id_args *argp;
        struct nfs41_exchange_id_res *resp;
+       unsigned long now = jiffies;
        int status;
 
        task = nfs4_run_exchange_id(clp, cred, sp4_how, NULL);
@@ -8223,6 +8281,8 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cre
        if (status != 0)
                goto out;
 
+       do_renew_lease(clp, now);
+
        clp->cl_clientid = resp->clientid;
        clp->cl_exchange_flags = resp->flags;
        clp->cl_seqid = resp->seqid;
@@ -8626,7 +8686,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
        case -EACCES:
        case -EAGAIN:
                goto out;
-       };
+       }
 
        clp->cl_seqid++;
        if (!status) {
@@ -10001,7 +10061,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .file_ops       = &nfs4_file_operations,
        .getroot        = nfs4_proc_get_root,
        .submount       = nfs4_submount,
-       .try_mount      = nfs4_try_mount,
+       .try_get_tree   = nfs4_try_get_tree,
        .getattr        = nfs4_proc_getattr,
        .setattr        = nfs4_proc_setattr,
        .lookup         = nfs4_proc_lookup,