📄 nfs4proc.c
字号:
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 + -