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

📄 nfs4proc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			continue;		rcu_read_unlock();		update_open_stateid(state, NULL, &stateid, open_mode);		goto out_return_state;	}	rcu_read_unlock();out:	return ERR_PTR(ret);out_return_state:	atomic_inc(&state->count);	return state;}static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data){	struct inode *inode;	struct nfs4_state *state = NULL;	struct nfs_delegation *delegation;	nfs4_stateid *deleg_stateid = NULL;	int ret;	if (!data->rpc_done) {		state = nfs4_try_open_cached(data);		goto out;	}	ret = -EAGAIN;	if (!(data->f_attr.valid & NFS_ATTR_FATTR))		goto err;	inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);	ret = PTR_ERR(inode);	if (IS_ERR(inode))		goto err;	ret = -ENOMEM;	state = nfs4_get_open_state(inode, data->owner);	if (state == NULL)		goto err_put_inode;	if (data->o_res.delegation_type != 0) {		int delegation_flags = 0;		rcu_read_lock();		delegation = rcu_dereference(NFS_I(inode)->delegation);		if (delegation)			delegation_flags = delegation->flags;		rcu_read_unlock();		if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))			nfs_inode_set_delegation(state->inode,					data->owner->so_cred,					&data->o_res);		else			nfs_inode_reclaim_delegation(state->inode,					data->owner->so_cred,					&data->o_res);	}	rcu_read_lock();	delegation = rcu_dereference(NFS_I(inode)->delegation);	if (delegation != NULL)		deleg_stateid = &delegation->stateid;	update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags);	rcu_read_unlock();	iput(inode);out:	return state;err_put_inode:	iput(inode);err:	return ERR_PTR(ret);}static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state){	struct nfs_inode *nfsi = NFS_I(state->inode);	struct nfs_open_context *ctx;	spin_lock(&state->inode->i_lock);	list_for_each_entry(ctx, &nfsi->open_files, list) {		if (ctx->state != state)			continue;		get_nfs_open_context(ctx);		spin_unlock(&state->inode->i_lock);		return ctx;	}	spin_unlock(&state->inode->i_lock);	return ERR_PTR(-ENOENT);}static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state){	struct nfs4_opendata *opendata;	opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);	if (opendata == NULL)		return ERR_PTR(-ENOMEM);	opendata->state = state;	atomic_inc(&state->count);	return opendata;}static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res){	struct nfs4_state *newstate;	int ret;	opendata->o_arg.open_flags = openflags;	memset(&opendata->o_res, 0, sizeof(opendata->o_res));	memset(&opendata->c_res, 0, sizeof(opendata->c_res));	nfs4_init_opendata_res(opendata);	ret = _nfs4_proc_open(opendata);	if (ret != 0)		return ret; 	newstate = nfs4_opendata_to_nfs4_state(opendata);	if (IS_ERR(newstate))		return PTR_ERR(newstate);	nfs4_close_state(&opendata->path, newstate, openflags);	*res = newstate;	return 0;}static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state){	struct nfs4_state *newstate;	int ret;	/* memory barrier prior to reading state->n_* */	clear_bit(NFS_DELEGATED_STATE, &state->flags);	smp_rmb();	if (state->n_rdwr != 0) {		ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);		if (ret != 0)			return ret;		if (newstate != state)			return -ESTALE;	}	if (state->n_wronly != 0) {		ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);		if (ret != 0)			return ret;		if (newstate != state)			return -ESTALE;	}	if (state->n_rdonly != 0) {		ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);		if (ret != 0)			return ret;		if (newstate != state)			return -ESTALE;	}	/*	 * We may have performed cached opens for all three recoveries.	 * Check if we need to update the current stateid.	 */	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&	    memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {		write_seqlock(&state->seqlock);		if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)			memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));		write_sequnlock(&state->seqlock);	}	return 0;}/* * OPEN_RECLAIM: * 	reclaim state on the server after a reboot. */static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state){	struct nfs_delegation *delegation;	struct nfs4_opendata *opendata;	int delegation_type = 0;	int status;	opendata = nfs4_open_recoverdata_alloc(ctx, state);	if (IS_ERR(opendata))		return PTR_ERR(opendata);	opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;	opendata->o_arg.fh = NFS_FH(state->inode);	rcu_read_lock();	delegation = rcu_dereference(NFS_I(state->inode)->delegation);	if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0)		delegation_type = delegation->type;	rcu_read_unlock();	opendata->o_arg.u.delegation_type = delegation_type;	status = nfs4_open_recover(opendata, state);	nfs4_opendata_put(opendata);	return status;}static int nfs4_do_open_reclaim(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_do_open_reclaim(ctx, state);		if (err != -NFS4ERR_DELAY)			break;		nfs4_handle_exception(server, err, &exception);	} while (exception.retry);	return err;}static int nfs4_open_reclaim(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_reclaim(ctx, state);	put_nfs_open_context(ctx);	return ret;}static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid){	struct nfs4_opendata *opendata;	int ret;	opendata = nfs4_open_recoverdata_alloc(ctx, state);	if (IS_ERR(opendata))		return PTR_ERR(opendata);	opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;	memcpy(opendata->o_arg.u.delegation.data, stateid->data,			sizeof(opendata->o_arg.u.delegation.data));	ret = nfs4_open_recover(opendata, state);	nfs4_opendata_put(opendata);	return ret;}int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid){	struct nfs4_exception exception = { };	struct nfs_server *server = NFS_SERVER(state->inode);	int err;	do {		err = _nfs4_open_delegation_recall(ctx, state, stateid);		switch (err) {			case 0:				return err;			case -NFS4ERR_STALE_CLIENTID:			case -NFS4ERR_STALE_STATEID:			case -NFS4ERR_EXPIRED:				/* Don't recall a delegation if it was lost */				nfs4_schedule_state_recovery(server->nfs_client);				return err;		}		err = nfs4_handle_exception(server, err, &exception);	} while (exception.retry);	return err;}static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata){	struct nfs4_opendata *data = calldata;	struct  rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],		.rpc_argp = &data->c_arg,		.rpc_resp = &data->c_res,		.rpc_cred = data->owner->so_cred,	};	data->timestamp = jiffies;	rpc_call_setup(task, &msg, 0);}static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata){	struct nfs4_opendata *data = calldata;	data->rpc_status = task->tk_status;	if (RPC_ASSASSINATED(task))		return;	if (data->rpc_status == 0) {		memcpy(data->o_res.stateid.data, data->c_res.stateid.data,				sizeof(data->o_res.stateid.data));		nfs_confirm_seqid(&data->owner->so_seqid, 0);		renew_lease(data->o_res.server, data->timestamp);		data->rpc_done = 1;	}	nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid);}static void nfs4_open_confirm_release(void *calldata){	struct nfs4_opendata *data = calldata;	struct nfs4_state *state = NULL;	/* If this request hasn't been cancelled, do nothing */	if (data->cancelled == 0)		goto out_free;	/* In case of error, no cleanup! */	if (!data->rpc_done)		goto out_free;	state = nfs4_opendata_to_nfs4_state(data);	if (!IS_ERR(state))		nfs4_close_state(&data->path, state, data->o_arg.open_flags);out_free:	nfs4_opendata_put(data);}static const struct rpc_call_ops nfs4_open_confirm_ops = {	.rpc_call_prepare = nfs4_open_confirm_prepare,	.rpc_call_done = nfs4_open_confirm_done,	.rpc_release = nfs4_open_confirm_release,};/* * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata */static int _nfs4_proc_open_confirm(struct nfs4_opendata *data){	struct nfs_server *server = NFS_SERVER(data->dir->d_inode);	struct rpc_task *task;	int status;	kref_get(&data->kref);	data->rpc_done = 0;	data->rpc_status = 0;	task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data);	if (IS_ERR(task))		return PTR_ERR(task);	status = nfs4_wait_for_completion_rpc_task(task);	if (status != 0) {		data->cancelled = 1;		smp_wmb();	} else		status = data->rpc_status;	rpc_put_task(task);	return status;}static void nfs4_open_prepare(struct rpc_task *task, void *calldata){	struct nfs4_opendata *data = calldata;	struct nfs4_state_owner *sp = data->owner;	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],		.rpc_argp = &data->o_arg,		.rpc_resp = &data->o_res,		.rpc_cred = sp->so_cred,	};		if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)		return;	/*	 * Check if we still need to send an OPEN call, or if we can use	 * a delegation instead.	 */	if (data->state != NULL) {		struct nfs_delegation *delegation;		if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL)))			goto out_no_action;		rcu_read_lock();		delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);		if (delegation != NULL &&		   (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) {			rcu_read_unlock();			goto out_no_action;		}		rcu_read_unlock();	}	/* Update sequence id. */	data->o_arg.id = sp->so_owner_id.id;	data->o_arg.clientid = sp->so_client->cl_clientid;	if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {		msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];		nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);	}	data->timestamp = jiffies;	rpc_call_setup(task, &msg, 0);	return;out_no_action:	task->tk_action = NULL;}static void nfs4_open_done(struct rpc_task *task, void *calldata){	struct nfs4_opendata *data = calldata;	data->rpc_status = task->tk_status;	if (RPC_ASSASSINATED(task))		return;	if (task->tk_status == 0) {		switch (data->o_res.f_attr->mode & S_IFMT) {			case S_IFREG:				break;			case S_IFLNK:				data->rpc_status = -ELOOP;				break;			case S_IFDIR:				data->rpc_status = -EISDIR;				break;			default:				data->rpc_status = -ENOTDIR;		}		renew_lease(data->o_res.server, data->timestamp);		if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))			nfs_confirm_seqid(&data->owner->so_seqid, 0);	}	nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid);	data->rpc_done = 1;}static void nfs4_open_release(void *calldata){	struct nfs4_opendata *data = calldata;	struct nfs4_state *state = NULL;	/* If this request hasn't been cancelled, do nothing */	if (data->cancelled == 0)		goto out_free;	/* In case of error, no cleanup! */	if (data->rpc_status != 0 || !data->rpc_done)		goto out_free;	/* In case we need an open_confirm, no cleanup! */	if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)		goto out_free;	state = nfs4_opendata_to_nfs4_state(data);	if (!IS_ERR(state))		nfs4_close_state(&data->path, state, data->o_arg.open_flags);out_free:	nfs4_opendata_put(data);}static const struct rpc_call_ops nfs4_open_ops = {	.rpc_call_prepare = nfs4_open_prepare,	.rpc_call_done = nfs4_open_done,	.rpc_release = nfs4_open_release,};/* * Note: On error, nfs4_proc_open will free the struct nfs4_opendata */static int _nfs4_proc_open(struct nfs4_opendata *data){	struct inode *dir = data->dir->d_inode;	struct nfs_server *server = NFS_SERVER(dir);	struct nfs_openargs *o_arg = &data->o_arg;	struct nfs_openres *o_res = &data->o_res;	struct rpc_task *task;	int status;	kref_get(&data->kref);	data->rpc_done = 0;	data->rpc_status = 0;	data->cancelled = 0;	task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data);	if (IS_ERR(task))		return PTR_ERR(task);	status = nfs4_wait_for_completion_rpc_task(task);	if (status != 0) {		data->cancelled = 1;		smp_wmb();	} else		status = data->rpc_status;	rpc_put_task(task);	if (status != 0 || !data->rpc_done)		return status;	if (o_res->fh.size == 0)		_nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr);	if (o_arg->open_flags & O_CREAT) {		update_changeattr(dir, &o_res->cinfo);

⌨️ 快捷键说明

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