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

📄 nfs4proc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);	put_rpccred(cred);	if (IS_ERR(state)) {		if (PTR_ERR(state) == -ENOENT) {			d_add(dentry, NULL);			nfs_set_verifier(dentry, nfs_save_change_attribute(dir));		}		nfs_unblock_sillyrename(parent);		return (struct dentry *)state;	}	res = d_add_unique(dentry, igrab(state->inode));	if (res != NULL)		path.dentry = res;	nfs_set_verifier(path.dentry, nfs_save_change_attribute(dir));	nfs_unblock_sillyrename(parent);	nfs4_intent_set_file(nd, &path, state);	return res;}intnfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd){	struct path path = {		.mnt = nd->mnt,		.dentry = dentry,	};	struct rpc_cred *cred;	struct nfs4_state *state;	cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);	if (IS_ERR(cred))		return PTR_ERR(cred);	state = nfs4_do_open(dir, &path, openflags, NULL, cred);	put_rpccred(cred);	if (IS_ERR(state)) {		switch (PTR_ERR(state)) {			case -EPERM:			case -EACCES:			case -EDQUOT:			case -ENOSPC:			case -EROFS:				lookup_instantiate_filp(nd, (struct dentry *)state, NULL);				return 1;			default:				goto out_drop;		}	}	if (state->inode == dentry->d_inode) {		nfs_set_verifier(dentry, nfs_save_change_attribute(dir));		nfs4_intent_set_file(nd, &path, state);		return 1;	}	nfs4_close_sync(&path, state, openflags);out_drop:	d_drop(dentry);	return 0;}static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle){	struct nfs4_server_caps_res res = {};	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],		.rpc_argp = fhandle,		.rpc_resp = &res,	};	int status;	status = rpc_call_sync(server->client, &msg, 0);	if (status == 0) {		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)			server->caps |= NFS_CAP_ACLS;		if (res.has_links != 0)			server->caps |= NFS_CAP_HARDLINKS;		if (res.has_symlinks != 0)			server->caps |= NFS_CAP_SYMLINKS;		server->acl_bitmask = res.acl_bitmask;	}	return status;}int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle){	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(server,				_nfs4_server_capabilities(server, fhandle),				&exception);	} while (exception.retry);	return err;}static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,		struct nfs_fsinfo *info){	struct nfs4_lookup_root_arg args = {		.bitmask = nfs4_fattr_bitmap,	};	struct nfs4_lookup_res res = {		.server = server,		.fattr = info->fattr,		.fh = fhandle,	};	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],		.rpc_argp = &args,		.rpc_resp = &res,	};	nfs_fattr_init(info->fattr);	return rpc_call_sync(server->client, &msg, 0);}static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,		struct nfs_fsinfo *info){	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(server,				_nfs4_lookup_root(server, fhandle, info),				&exception);	} while (exception.retry);	return err;}/* * get the file handle for the "/" directory on the server */static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,			      struct nfs_fsinfo *info){	int status;	status = nfs4_lookup_root(server, fhandle, info);	if (status == 0)		status = nfs4_server_capabilities(server, fhandle);	if (status == 0)		status = nfs4_do_fsinfo(server, fhandle, info);	return nfs4_map_errors(status);}/* * Get locations and (maybe) other attributes of a referral. * Note that we'll actually follow the referral later when * we detect fsid mismatch in inode revalidation */static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle){	int status = -ENOMEM;	struct page *page = NULL;	struct nfs4_fs_locations *locations = NULL;	page = alloc_page(GFP_KERNEL);	if (page == NULL)		goto out;	locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);	if (locations == NULL)		goto out;	status = nfs4_proc_fs_locations(dir, name, locations, page);	if (status != 0)		goto out;	/* Make sure server returned a different fsid for the referral */	if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {		dprintk("%s: server did not return a different fsid for a referral at %s\n", __FUNCTION__, name->name);		status = -EIO;		goto out;	}	memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));	fattr->valid |= NFS_ATTR_FATTR_V4_REFERRAL;	if (!fattr->mode)		fattr->mode = S_IFDIR;	memset(fhandle, 0, sizeof(struct nfs_fh));out:	if (page)		__free_page(page);	if (locations)		kfree(locations);	return status;}static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr){	struct nfs4_getattr_arg args = {		.fh = fhandle,		.bitmask = server->attr_bitmask,	};	struct nfs4_getattr_res res = {		.fattr = fattr,		.server = server,	};	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],		.rpc_argp = &args,		.rpc_resp = &res,	};		nfs_fattr_init(fattr);	return rpc_call_sync(server->client, &msg, 0);}static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr){	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(server,				_nfs4_proc_getattr(server, fhandle, fattr),				&exception);	} while (exception.retry);	return err;}/*  * The file is not closed if it is opened due to the a request to change * the size of the file. The open call will not be needed once the * VFS layer lookup-intents are implemented. * * Close is called when the inode is destroyed. * If we haven't opened the file for O_WRONLY, we * need to in the size_change case to obtain a stateid. * * Got race? * Because OPEN is always done by name in nfsv4, it is * possible that we opened a different file by the same * name.  We can recognize this race condition, but we * can't do anything about it besides returning an error. * * This will be fixed with VFS changes (lookup-intent). */static intnfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,		  struct iattr *sattr){	struct rpc_cred *cred;	struct inode *inode = dentry->d_inode;	struct nfs_open_context *ctx;	struct nfs4_state *state = NULL;	int status;	nfs_fattr_init(fattr);		cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);	if (IS_ERR(cred))		return PTR_ERR(cred);	/* Search for an existing open(O_WRITE) file */	ctx = nfs_find_open_context(inode, cred, FMODE_WRITE);	if (ctx != NULL)		state = ctx->state;	status = nfs4_do_setattr(inode, fattr, sattr, state);	if (status == 0)		nfs_setattr_update_inode(inode, sattr);	if (ctx != NULL)		put_nfs_open_context(ctx);	put_rpccred(cred);	return status;}static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh,		const struct qstr *name, struct nfs_fh *fhandle,		struct nfs_fattr *fattr){	int		       status;	struct nfs4_lookup_arg args = {		.bitmask = server->attr_bitmask,		.dir_fh = dirfh,		.name = name,	};	struct nfs4_lookup_res res = {		.server = server,		.fattr = fattr,		.fh = fhandle,	};	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],		.rpc_argp = &args,		.rpc_resp = &res,	};	nfs_fattr_init(fattr);	dprintk("NFS call  lookupfh %s\n", name->name);	status = rpc_call_sync(server->client, &msg, 0);	dprintk("NFS reply lookupfh: %d\n", status);	return status;}static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,			      struct qstr *name, struct nfs_fh *fhandle,			      struct nfs_fattr *fattr){	struct nfs4_exception exception = { };	int err;	do {		err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr);		/* FIXME: !!!! */		if (err == -NFS4ERR_MOVED) {			err = -EREMOTE;			break;		}		err = nfs4_handle_exception(server, err, &exception);	} while (exception.retry);	return err;}static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name,		struct nfs_fh *fhandle, struct nfs_fattr *fattr){	int status;		dprintk("NFS call  lookup %s\n", name->name);	status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr);	if (status == -NFS4ERR_MOVED)		status = nfs4_get_referral(dir, name, fattr, fhandle);	dprintk("NFS reply lookup: %d\n", status);	return status;}static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr){	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(NFS_SERVER(dir),				_nfs4_proc_lookup(dir, name, fhandle, fattr),				&exception);	} while (exception.retry);	return err;}static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry){	struct nfs_server *server = NFS_SERVER(inode);	struct nfs_fattr fattr;	struct nfs4_accessargs args = {		.fh = NFS_FH(inode),		.bitmask = server->attr_bitmask,	};	struct nfs4_accessres res = {		.server = server,		.fattr = &fattr,	};	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],		.rpc_argp = &args,		.rpc_resp = &res,		.rpc_cred = entry->cred,	};	int mode = entry->mask;	int status;	/*	 * Determine which access bits we want to ask for...	 */	if (mode & MAY_READ)		args.access |= NFS4_ACCESS_READ;	if (S_ISDIR(inode->i_mode)) {		if (mode & MAY_WRITE)			args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;		if (mode & MAY_EXEC)			args.access |= NFS4_ACCESS_LOOKUP;	} else {		if (mode & MAY_WRITE)			args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;		if (mode & MAY_EXEC)			args.access |= NFS4_ACCESS_EXECUTE;	}	nfs_fattr_init(&fattr);	status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);	if (!status) {		entry->mask = 0;		if (res.access & NFS4_ACCESS_READ)			entry->mask |= MAY_READ;		if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))			entry->mask |= MAY_WRITE;		if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))			entry->mask |= MAY_EXEC;		nfs_refresh_inode(inode, &fattr);	}	return status;}static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry){	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(NFS_SERVER(inode),				_nfs4_proc_access(inode, entry),				&exception);	} while (exception.retry);	return err;}/* * TODO: For the time being, we don't try to get any attributes * along with any of the zero-copy operations READ, READDIR, * READLINK, WRITE. * * In the case of the first three, we want to put the GETATTR * after the read-type operation -- this is because it is hard * to predict the length of a GETATTR response in v4, and thus * align the READ data correctly.  This means that the GETATTR * may end up partially falling into the page cache, and we should * shift it into the 'tail' of the xdr_buf before processing. * To do this efficiently, we need to know the total length * of data received, which doesn't seem to be available outside * of the RPC layer. * * In the case of WRITE, we also want to put the GETATTR after * the operation -- in this case because we want to make sure * we get the post-operation mtime and size.  This means that * we can't use xdr_encode_pages() as written: we need a variant * of it which would leave room in the 'tail' iovec. * * Both of these changes to the XDR layer would in fact be quite * minor, but I decided to leave them for a subsequent patch. */static int _nfs4_proc_readlink(struct inode *inode, struct page *page,		unsigned int pgbase, unsigned int pglen){	struct nfs4_readlink args = {		.fh       = NFS_FH(inode),		.pgbase	  = pgbase,		.pglen    = pglen,		.pages    = &page,	};	struct rpc_message msg = {		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],		.rpc_argp = &args,		.rpc_resp = NULL,	};	return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);}static int nfs4_proc_readlink(struct inode *inode, struct page *page,		unsigned int pgbase, unsigned int pglen){	struct nfs4_exception exception = { };	int err;	do {		err = nfs4_handle_exception(NFS_SERVER(inode),				_nfs4_proc_readlink(inode, page, pgbase, pglen),				&exception);	} while (exception.retry);	return err;}/* * Got race? * We will need to arrange for the VFS layer to provide an atomic open. * Until then, this create/open method is prone to inefficiency and race * conditions due to the lookup, create, and open VFS calls from sys_open() * placed on the wire. * * Given the above sorry state of affairs, I'm simply sending an OPEN. * The file will be opened again in the subsequent VFS open call * (nfs4_proc_file_open). * * The open for read will just hang around to be used by any process that

⌨️ 快捷键说明

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