📄 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/smp_lock.h>#define NFSDBG_FACILITY NFSDBG_PROCextern struct rpc_procinfo nfs3_procedures[];/* 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; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(NFS_JUKEBOX_RETRY_TIME); res = -ERESTARTSYS; } while (!signalled()); rpc_clnt_sigunmask(clnt, &oldset); return res;}static inline intnfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags){ struct rpc_message msg = { .rpc_proc = &nfs3_procedures[proc], .rpc_argp = argp, .rpc_resp = resp, }; return nfs3_rpc_wrapper(clnt, &msg, flags);}#define rpc_call(clnt, proc, argp, resp, flags) \ nfs3_rpc_call_wrapper(clnt, proc, argp, resp, flags)#define rpc_call_sync(clnt, msg, flags) \ nfs3_rpc_wrapper(clnt, msg, flags)static intnfs3_async_handle_jukebox(struct rpc_task *task){ if (task->tk_status != -EJUKEBOX) return 0; task->tk_status = 0; rpc_restart_call(task); rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); return 1;}/* * Bare-bones access to getattr: this is for nfs_read_super. */static intnfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info){ int status; dprintk("%s: call fsinfo\n", __FUNCTION__); info->fattr->valid = 0; status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status); if (!(info->fattr->valid & NFS_ATTR_FATTR)) { status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0); dprintk("%s: reply getattr %d\n", __FUNCTION__, status); } 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){ int status; dprintk("NFS call getattr\n"); fattr->valid = 0; status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply getattr\n"); 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, }; int status; dprintk("NFS call setattr\n"); fattr->valid = 0; status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0); dprintk("NFS reply setattr\n"); 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 }; int status; dprintk("NFS call lookup %s\n", name->name); dir_attr.valid = 0; fattr->valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0); if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR)) status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR, fhandle, fattr, 0); dprintk("NFS reply lookup: %d\n", status); if (status >= 0) status = nfs_refresh_inode(dir, &dir_attr); 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"); fattr.valid = 0; 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; } 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, status = %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 }; int status; dprintk("NFS call readlink\n"); fattr.valid = 0; status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK, &args, &fattr, 0); nfs_refresh_inode(inode, &fattr); dprintk("NFS reply readlink: %d\n", status); return status;}static int nfs3_proc_read(struct nfs_read_data *rdata){ int flags = rdata->flags; struct inode * inode = rdata->inode; struct nfs_fattr * fattr = rdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_READ], .rpc_argp = &rdata->args, .rpc_resp = &rdata->res, .rpc_cred = rdata->cred, }; int status; dprintk("NFS call read %d @ %Ld\n", rdata->args.count, (long long) rdata->args.offset); fattr->valid = 0; status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) nfs_refresh_inode(inode, fattr); dprintk("NFS reply read: %d\n", status); return status;}static int nfs3_proc_write(struct nfs_write_data *wdata){ int rpcflags = wdata->flags; struct inode * inode = wdata->inode; struct nfs_fattr * fattr = wdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_WRITE], .rpc_argp = &wdata->args, .rpc_resp = &wdata->res, .rpc_cred = wdata->cred, }; int status; dprintk("NFS call write %d @ %Ld\n", wdata->args.count, (long long) wdata->args.offset); fattr->valid = 0; status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); if (status >= 0) nfs_refresh_inode(inode, fattr); dprintk("NFS reply write: %d\n", status); return status < 0? status : wdata->res.count;}static int nfs3_proc_commit(struct nfs_write_data *cdata){ struct inode * inode = cdata->inode; struct nfs_fattr * fattr = cdata->res.fattr; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_COMMIT], .rpc_argp = &cdata->args, .rpc_resp = &cdata->res, .rpc_cred = cdata->cred, }; int status; dprintk("NFS call commit %d @ %Ld\n", cdata->args.count, (long long) cdata->args.offset); fattr->valid = 0; status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status >= 0) nfs_refresh_inode(inode, fattr); dprintk("NFS reply commit: %d\n", status); return status;}/* * Create a regular file. * For now, we don't implement O_EXCL. */static struct inode *nfs3_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr, int flags){ struct nfs_fh fhandle; struct nfs_fattr fattr; struct nfs_fattr dir_attr; struct nfs3_createargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len, .sattr = sattr, }; struct nfs3_diropres res = { .dir_attr = &dir_attr, .fh = &fhandle, .fattr = &fattr }; int status; dprintk("NFS call create %s\n", 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; }again: dir_attr.valid = 0; fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 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 == NFSERR_NOTSUPP) { 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 exit; } goto again; }exit: dprintk("NFS reply create: %d\n", status); if (status != 0) goto out; if (fhandle.size == 0 || !(fattr.valid & NFS_ATTR_FATTR)) { status = nfs3_proc_lookup(dir, name, &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) { struct nfs3_sattrargs arg = { .fh = &fhandle, .sattr = sattr, }; 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) */ fattr.valid = 0; status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR, &arg, &fattr, 0); dprintk("NFS reply setattr (post-create): %d\n", status); } if (status == 0) { struct inode *inode; inode = nfs_fhget(dir->i_sb, &fhandle, &fattr); if (inode) return inode; status = -ENOMEM; }out: return ERR_PTR(status);}static intnfs3_proc_remove(struct inode *dir, struct qstr *name){ struct nfs_fattr dir_attr; struct nfs3_diropargs arg = { .fh = NFS_FH(dir), .name = name->name, .len = name->len }; struct rpc_message msg = { .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE], .rpc_argp = &arg, .rpc_resp = &dir_attr, }; int status; dprintk("NFS call remove %s\n", name->name); dir_attr.valid = 0; status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); nfs_refresh_inode(dir, &dir_attr); dprintk("NFS reply remove: %d\n", status); return status;}static intnfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name){ struct unlinkxdr { struct nfs3_diropargs arg; struct nfs_fattr res; } *ptr; ptr = (struct unlinkxdr *)kmalloc(sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; ptr->arg.fh = NFS_FH(dir->d_inode); ptr->arg.name = name->name; ptr->arg.len = name->len; ptr->res.valid = 0; msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; msg->rpc_argp = &ptr->arg; msg->rpc_resp = &ptr->res; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -