⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs4proc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		nfs_post_op_update_inode(dir, o_res->dir_attr);	} else		nfs_refresh_inode(dir, o_res->dir_attr);	if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {		status = _nfs4_proc_open_confirm(data);		if (status != 0)			return status;	}	if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))		_nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);	return 0;}static int nfs4_recover_expired_lease(struct nfs_server *server){	struct nfs_client *clp = server->nfs_client;	int ret;	for (;;) {		ret = nfs4_wait_clnt_recover(server->client, clp);		if (ret != 0)			return ret;		if (!test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))			break;		nfs4_schedule_state_recovery(clp);	}	return 0;}/* * OPEN_EXPIRED: * 	reclaim state on the server after a network partition. * 	Assumes caller holds the appropriate lock */static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state){	struct nfs4_opendata *opendata;	int ret;	opendata = nfs4_open_recoverdata_alloc(ctx, state);	if (IS_ERR(opendata))		return PTR_ERR(opendata);	ret = nfs4_open_recover(opendata, state);	if (ret == -ESTALE) {		/* Invalidate the state owner so we don't ever use it again */		nfs4_drop_state_owner(state->owner);		d_drop(ctx->path.dentry);	}	nfs4_opendata_put(opendata);	return ret;}static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state){	struct nfs_server *server = NFS_SERVER(state->inode);	struct nfs4_exception exception = { };	int err;	do {		err = _nfs4_open_expired(ctx, state);		if (err == -NFS4ERR_DELAY)			nfs4_handle_exception(server, err, &exception);	} while (exception.retry);	return err;}static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state){	struct nfs_open_context *ctx;	int ret;	ctx = nfs4_state_find_open_context(state);	if (IS_ERR(ctx))		return PTR_ERR(ctx);	ret = nfs4_do_open_expired(ctx, state);	put_nfs_open_context(ctx);	return ret;}/* * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* * fields corresponding to attributes that were used to store the verifier. * Make sure we clobber those fields in the later setattr call */static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr){	if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&	    !(sattr->ia_valid & ATTR_ATIME_SET))		sattr->ia_valid |= ATTR_ATIME;	if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&	    !(sattr->ia_valid & ATTR_MTIME_SET))		sattr->ia_valid |= ATTR_MTIME;}/* * Returns a referenced nfs4_state */static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res){	struct nfs4_state_owner  *sp;	struct nfs4_state     *state = NULL;	struct nfs_server       *server = NFS_SERVER(dir);	struct nfs_client *clp = server->nfs_client;	struct nfs4_opendata *opendata;	int status;	/* Protect against reboot recovery conflicts */	status = -ENOMEM;	if (!(sp = nfs4_get_state_owner(server, cred))) {		dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");		goto out_err;	}	status = nfs4_recover_expired_lease(server);	if (status != 0)		goto err_put_state_owner;	if (path->dentry->d_inode != NULL)		nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));	down_read(&clp->cl_sem);	status = -ENOMEM;	opendata = nfs4_opendata_alloc(path, sp, flags, sattr);	if (opendata == NULL)		goto err_release_rwsem;	if (path->dentry->d_inode != NULL)		opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp);	status = _nfs4_proc_open(opendata);	if (status != 0)		goto err_opendata_put;	if (opendata->o_arg.open_flags & O_EXCL)		nfs4_exclusive_attrset(opendata, sattr);	state = nfs4_opendata_to_nfs4_state(opendata);	status = PTR_ERR(state);	if (IS_ERR(state))		goto err_opendata_put;	nfs4_opendata_put(opendata);	nfs4_put_state_owner(sp);	up_read(&clp->cl_sem);	*res = state;	return 0;err_opendata_put:	nfs4_opendata_put(opendata);err_release_rwsem:	up_read(&clp->cl_sem);err_put_state_owner:	nfs4_put_state_owner(sp);out_err:	*res = NULL;	return status;}static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred){	struct nfs4_exception exception = { };	struct nfs4_state *res;	int status;	do {		status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);		if (status == 0)			break;		/* NOTE: BAD_SEQID means the server and client disagree about the		 * book-keeping w.r.t. state-changing operations		 * (OPEN/CLOSE/LOCK/LOCKU...)		 * It is actually a sign of a bug on the client or on the server.		 *		 * If we receive a BAD_SEQID error in the particular case of		 * doing an OPEN, we assume that nfs_increment_open_seqid() will		 * have unhashed the old state_owner for us, and that we can		 * therefore safely retry using a new one. We should still warn		 * the user though...		 */		if (status == -NFS4ERR_BAD_SEQID) {			printk(KERN_WARNING "NFS: v4 server %s "					" returned a bad sequence-id error!\n",					NFS_SERVER(dir)->nfs_client->cl_hostname);			exception.retry = 1;			continue;		}		/*		 * BAD_STATEID on OPEN means that the server cancelled our		 * state before it received the OPEN_CONFIRM.		 * Recover by retrying the request as per the discussion		 * on Page 181 of RFC3530.		 */		if (status == -NFS4ERR_BAD_STATEID) {			exception.retry = 1;			continue;		}		if (status == -EAGAIN) {			/* We must have found a delegation */			exception.retry = 1;			continue;		}		res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),					status, &exception));	} while (exception.retry);	return res;}static int _nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,                struct iattr *sattr, struct nfs4_state *state){	struct nfs_server *server = NFS_SERVER(inode);        struct nfs_setattrargs  arg = {                .fh             = NFS_FH(inode),                .iap            = sattr,		.server		= server,		.bitmask = server->attr_bitmask,        };        struct nfs_setattrres  res = {		.fattr		= fattr,		.server		= server,        };        struct rpc_message msg = {                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],                .rpc_argp       = &arg,                .rpc_resp       = &res,        };	unsigned long timestamp = jiffies;	int status;	nfs_fattr_init(fattr);	if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {		/* Use that stateid */	} else if (state != NULL) {		msg.rpc_cred = state->owner->so_cred;		nfs4_copy_stateid(&arg.stateid, state, current->files);	} else		memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));	status = rpc_call_sync(server->client, &msg, 0);	if (status == 0 && state != NULL)		renew_lease(server, timestamp);	return status;}static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,                struct iattr *sattr, struct nfs4_state *state){	struct nfs_server *server = NFS_SERVER(inode);	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(server,				_nfs4_do_setattr(inode, fattr, sattr, state),				&exception);	} while (exception.retry);	return err;}struct nfs4_closedata {	struct path path;	struct inode *inode;	struct nfs4_state *state;	struct nfs_closeargs arg;	struct nfs_closeres res;	struct nfs_fattr fattr;	unsigned long timestamp;};static void nfs4_free_closedata(void *data){	struct nfs4_closedata *calldata = data;	struct nfs4_state_owner *sp = calldata->state->owner;	nfs4_put_open_state(calldata->state);	nfs_free_seqid(calldata->arg.seqid);	nfs4_put_state_owner(sp);	dput(calldata->path.dentry);	mntput(calldata->path.mnt);	kfree(calldata);}static void nfs4_close_done(struct rpc_task *task, void *data){	struct nfs4_closedata *calldata = data;	struct nfs4_state *state = calldata->state;	struct nfs_server *server = NFS_SERVER(calldata->inode);	if (RPC_ASSASSINATED(task))		return;        /* hmm. we are done with the inode, and in the process of freeing	 * the state_owner. we keep this around to process errors	 */	nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid);	switch (task->tk_status) {		case 0:			nfs_set_open_stateid(state, &calldata->res.stateid, 0);			renew_lease(server, calldata->timestamp);			break;		case -NFS4ERR_STALE_STATEID:		case -NFS4ERR_EXPIRED:			break;		default:			if (nfs4_async_handle_error(task, server) == -EAGAIN) {				rpc_restart_call(task);				return;			}	}	nfs_refresh_inode(calldata->inode, calldata->res.fattr);}static void nfs4_close_prepare(struct rpc_task *task, void *data){	struct nfs4_closedata *calldata = data;	struct nfs4_state *state = calldata->state;	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],		.rpc_argp = &calldata->arg,		.rpc_resp = &calldata->res,		.rpc_cred = state->owner->so_cred,	};	int clear_rd, clear_wr, clear_rdwr;	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)		return;	clear_rd = clear_wr = clear_rdwr = 0;	spin_lock(&state->owner->so_lock);	/* Calculate the change in open mode */	if (state->n_rdwr == 0) {		if (state->n_rdonly == 0) {			clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags);			clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);		}		if (state->n_wronly == 0) {			clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags);			clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);		}	}	spin_unlock(&state->owner->so_lock);	if (!clear_rd && !clear_wr && !clear_rdwr) {		/* Note: exit _without_ calling nfs4_close_done */		task->tk_action = NULL;		return;	}	nfs_fattr_init(calldata->res.fattr);	if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) {		msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];		calldata->arg.open_flags = FMODE_READ;	} else if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) {		msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];		calldata->arg.open_flags = FMODE_WRITE;	}	calldata->timestamp = jiffies;	rpc_call_setup(task, &msg, 0);}static const struct rpc_call_ops nfs4_close_ops = {	.rpc_call_prepare = nfs4_close_prepare,	.rpc_call_done = nfs4_close_done,	.rpc_release = nfs4_free_closedata,};/*  * It is possible for data to be read/written from a mem-mapped file  * after the sys_close call (which hits the vfs layer as a flush). * This means that we can't safely call nfsv4 close on a file until  * the inode is cleared. This in turn means that we are not good * NFSv4 citizens - we do not indicate to the server to update the file's  * share state even when we are done with one of the three share  * stateid's in the inode. * * NOTE: Caller must be holding the sp->so_owner semaphore! */int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait){	struct nfs_server *server = NFS_SERVER(state->inode);	struct nfs4_closedata *calldata;	struct nfs4_state_owner *sp = state->owner;	struct rpc_task *task;	int status = -ENOMEM;	calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);	if (calldata == NULL)		goto out;	calldata->inode = state->inode;	calldata->state = state;	calldata->arg.fh = NFS_FH(state->inode);	calldata->arg.stateid = &state->open_stateid;	/* Serialization for the sequence id */	calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);	if (calldata->arg.seqid == NULL)		goto out_free_calldata;	calldata->arg.bitmask = server->attr_bitmask;	calldata->res.fattr = &calldata->fattr;	calldata->res.server = server;	calldata->path.mnt = mntget(path->mnt);	calldata->path.dentry = dget(path->dentry);	task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata);	if (IS_ERR(task))		return PTR_ERR(task);	status = 0;	if (wait)		status = rpc_wait_for_completion_task(task);	rpc_put_task(task);	return status;out_free_calldata:	kfree(calldata);out:	nfs4_put_open_state(state);	nfs4_put_state_owner(sp);	return status;}static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state){	struct file *filp;	int ret;	/* If the open_intent is for execute, we have an extra check to make */	if (nd->intent.open.flags & FMODE_EXEC) {		ret = nfs_may_open(state->inode,				state->owner->so_cred,				nd->intent.open.flags);		if (ret < 0)			goto out_close;	}	filp = lookup_instantiate_filp(nd, path->dentry, NULL);	if (!IS_ERR(filp)) {		struct nfs_open_context *ctx;		ctx = nfs_file_open_context(filp);		ctx->state = state;		return 0;	}	ret = PTR_ERR(filp);out_close:	nfs4_close_sync(path, state, nd->intent.open.flags);	return ret;}struct dentry *nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd){	struct dentry *parent;	struct path path = {		.mnt = nd->mnt,		.dentry = dentry,	};	struct iattr attr;	struct rpc_cred *cred;	struct nfs4_state *state;	struct dentry *res;	if (nd->flags & LOOKUP_CREATE) {		attr.ia_mode = nd->intent.open.create_mode;		attr.ia_valid = ATTR_MODE;		if (!IS_POSIXACL(dir))			attr.ia_mode &= ~current->fs->umask;	} else {		attr.ia_valid = 0;		BUG_ON(nd->intent.open.flags & O_CREAT);	}	cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);	if (IS_ERR(cred))		return (struct dentry *)cred;	parent = dentry->d_parent;	/* Protect against concurrent sillydeletes */	nfs_block_sillyrename(parent);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -