📄 nfs3proc.c
字号:
/* * linux/fs/nfs/nfs3proc.c * * Client-side NFSv3 procedures stubs. * * Copyright (C) 1997, Olaf Kirch */#include <linux/mm.h>#include <linux/utsname.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/sunrpc/clnt.h>#include <linux/nfs.h>#include <linux/nfs3.h>#include <linux/nfs_fs.h>#include <linux/nfs_page.h>#include <linux/lockd/bind.h>#include <linux/nfs_mount.h>#include "iostat.h"#include "internal.h"#define NFSDBG_FACILITY NFSDBG_PROC/* A wrapper to handle the EJUKEBOX error message */static intnfs3_rpc_wrapper(struct rpc_clnt *clnt, struct rpc_message *msg, int flags){ sigset_t oldset; int res; rpc_clnt_sigmask(clnt, &oldset); do { res = rpc_call_sync(clnt, msg, flags); if (res != -EJUKEBOX) break; schedule_timeout_interruptible(NFS_JUKEBOX_RETRY_TIME); res = -ERESTARTSYS; } while (!signalled()); rpc_clnt_sigunmask(clnt, &oldset); return res;}#define rpc_call_sync(clnt, msg, flags) nfs3_rpc_wrapper(clnt, msg, flags)static intnfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode){ if (task->tk_status != -EJUKEBOX) return 0; nfs_inc_stats(inode, NFSIOS_DELAY); task->tk_status = 0; rpc_restart_call(task); rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); return 1;}static intdo_proc_get_root(struct rpc_clnt *client, struct nfs_fh *fhandle, struct nfs_fsinfo *info){ struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_FSINFO], .rpc_argp = fhandle, .rpc_resp = info, }; int status; dprintk("%s: call fsinfo\n", __FUNCTION__); nfs_fattr_init(info->fattr); status = rpc_call_sync(client, &msg, 0); dprintk("%s: reply fsinfo: %d\n", __FUNCTION__, status); if (!(info->fattr->valid & NFS_ATTR_FATTR)) { msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; msg.rpc_resp = info->fattr; status = rpc_call_sync(client, &msg, 0); dprintk("%s: reply getattr: %d\n", __FUNCTION__, status); } return status;}/* * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb */static intnfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info){ int status; status = do_proc_get_root(server->client, fhandle, info); if (status && server->nfs_client->cl_rpcclient != server->client) status = do_proc_get_root(server->nfs_client->cl_rpcclient, fhandle, info); return status;}/* * One function for each procedure in the NFS protocol. */static intnfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr){ struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR], .rpc_argp = fhandle, .rpc_resp = fattr, }; int status; dprintk("NFS call getattr\n"); nfs_fattr_init(fattr); status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply getattr: %d\n", status); return status;}static intnfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, struct iattr *sattr){ struct inode *inode = dentry->d_inode; struct nfs3_sattrargs arg = { .fh = NFS_FH(inode), .sattr = sattr, }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_SETATTR], .rpc_argp = &arg, .rpc_resp = fattr, }; int status; dprintk("NFS call setattr\n"); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status == 0) nfs_setattr_update_inode(inode, sattr); dprintk("NFS reply setattr: %d\n", status); return status;}static intnfs3_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr){ struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct nfs3_diropres res = { .dir_attr = &dir_attr, .fh = fhandle, .fattr = fattr }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_LOOKUP], .rpc_argp = &arg, .rpc_resp = &res, }; int status; dprintk("NFS call lookup %s\n", name->name); nfs_fattr_init(&dir_attr); nfs_fattr_init(fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) { msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR]; msg.rpc_argp = fhandle; msg.rpc_resp = fattr; status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); } dprintk("NFS reply lookup: %d\n", status); return status;}static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry){ struct nfs_fattr fattr; struct nfs3_accessargs arg = { .fh = NFS_FH(inode), }; struct nfs3_accessres res = { .fattr = &fattr, }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_ACCESS], .rpc_argp = &arg, .rpc_resp = &res, .rpc_cred = entry->cred, }; int mode = entry->mask; int status; dprintk("NFS call access\n"); if (mode & MAY_READ) arg.access |= NFS3_ACCESS_READ; if (S_ISDIR(inode->i_mode)) { if (mode & MAY_WRITE) arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE; if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_LOOKUP; } else { if (mode & MAY_WRITE) arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND; if (mode & MAY_EXEC) arg.access |= NFS3_ACCESS_EXECUTE; } nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_refresh_inode(inode, &fattr); if (status == 0) { entry->mask = 0; if (res.access & NFS3_ACCESS_READ) entry->mask |= MAY_READ; if (res.access & (NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE)) entry->mask |= MAY_WRITE; if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE)) entry->mask |= MAY_EXEC; } dprintk("NFS reply access: %d\n", status); return status;}static int nfs3_proc_readlink(struct inode *inode, struct page *page, unsigned int pgbase, unsigned int pglen){ struct nfs_fattr fattr; struct nfs3_readlinkargs args = { .fh = NFS_FH(inode), .pgbase = pgbase, .pglen = pglen, .pages = &page }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_READLINK], .rpc_argp = &args, .rpc_resp = &fattr, }; int status; dprintk("NFS call readlink\n"); nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply readlink: %d\n", status); return status;}/* * Create a regular file. * For now, we don't implement O_EXCL. */static intnfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd){ struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_fattr dir_attr; struct nfs3_createargs arg = { .fh = NFS_FH(dir), .name = dentry->d_name.name, .len = dentry->d_name.len, .sattr = sattr, }; struct nfs3_diropres res = { .dir_attr = &dir_attr, .fh = &fhandle, .fattr = &fattr }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_CREATE], .rpc_argp = &arg, .rpc_resp = &res, }; mode_t mode = sattr->ia_mode; int status; dprintk("NFS call create %s\n", dentry->d_name.name); arg.createmode = NFS3_CREATE_UNCHECKED; if (flags & O_EXCL) { arg.createmode = NFS3_CREATE_EXCLUSIVE; arg.verifier[0] = jiffies; arg.verifier[1] = current->pid; } sattr->ia_mode &= ~current->fs->umask;again: nfs_fattr_init(&dir_attr); nfs_fattr_init(&fattr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); /* If the server doesn't support the exclusive creation semantics, * try again with simple 'guarded' mode. */ if (status == -ENOTSUPP) { switch (arg.createmode) { case NFS3_CREATE_EXCLUSIVE: arg.createmode = NFS3_CREATE_GUARDED; break; case NFS3_CREATE_GUARDED: arg.createmode = NFS3_CREATE_UNCHECKED; break; case NFS3_CREATE_UNCHECKED: goto out; } goto again; } if (status == 0) status = nfs_instantiate(dentry, &fhandle, &fattr); if (status != 0) goto out; /* When we created the file with exclusive semantics, make * sure we set the attributes afterwards. */ if (arg.createmode == NFS3_CREATE_EXCLUSIVE) { dprintk("NFS call setattr (post-create)\n"); if (!(sattr->ia_valid & ATTR_ATIME_SET)) sattr->ia_valid |= ATTR_ATIME; if (!(sattr->ia_valid & ATTR_MTIME_SET)) sattr->ia_valid |= ATTR_MTIME; /* Note: we could use a guarded setattr here, but I'm * not sure this buys us anything (and I'd have * to revamp the NFSv3 XDR code) */ status = nfs3_proc_setattr(dentry, &fattr, sattr); nfs_post_op_update_inode(dentry->d_inode, &fattr); dprintk("NFS reply setattr (post-create): %d\n", status); } if (status != 0) goto out; status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);out: dprintk("NFS reply create: %d\n", status); return status;}static intnfs3_proc_remove(struct inode *dir, struct qstr *name){ struct nfs_removeargs arg = { .fh = NFS_FH(dir), .name.len = name->len, .name.name = name->name, }; struct nfs_removeres res; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], .rpc_argp = &arg, .rpc_resp = &res, }; int status; dprintk("NFS call remove %s\n", name->name); nfs_fattr_init(&res.dir_attr); status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_post_op_update_inode(dir, &res.dir_attr); dprintk("NFS reply remove: %d\n", status); return status;}static voidnfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir){ msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];}static intnfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir){ struct nfs_removeres *res; if (nfs3_async_handle_jukebox(task, dir)) return 0; res = task->tk_msg.rpc_resp; nfs_post_op_update_inode(dir, &res->dir_attr); return 1;}static intnfs3_proc_rename(struct inode *old_dir, struct qstr *old_name, struct inode *new_dir, struct qstr *new_name){ struct nfs_fattr old_dir_attr, new_dir_attr; struct nfs3_renameargs arg = { .fromfh = NFS_FH(old_dir), .fromname = old_name->name, .fromlen = old_name->len, .tofh = NFS_FH(new_dir), .toname = new_name->name, .tolen = new_name->len }; struct nfs3_renameres res = { .fromattr = &old_dir_attr, .toattr = &new_dir_attr }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_RENAME], .rpc_argp = &arg, .rpc_resp = &res, }; int status; dprintk("NFS call rename %s -> %s\n", old_name->name, new_name->name); nfs_fattr_init(&old_dir_attr); nfs_fattr_init(&new_dir_attr); status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0); nfs_post_op_update_inode(old_dir, &old_dir_attr); nfs_post_op_update_inode(new_dir, &new_dir_attr); dprintk("NFS reply rename: %d\n", status); return status;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -