diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 124 | 
1 files changed, 92 insertions, 32 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 76d37161409a..69b7ab7a5815 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -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 @@ out:  	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 @@ out:   */  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 @@ out_free:  			__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,  |