diff options
Diffstat (limited to 'fs/nfs/proc.c')
-rw-r--r-- | fs/nfs/proc.c | 1083 |
1 files changed, 169 insertions, 914 deletions
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ff71bd631..714101bb7 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -21,1017 +21,272 @@ * it decodes the packet. * * Feel free to fix it and mail me the diffs if it worries you. + * + * Completely rewritten to support the new RPC call interface; + * rewrote and moved the entire XDR stuff to xdr.c + * --Olaf Kirch June 1996 */ -/* - * Defining NFS_PROC_DEBUG causes a lookup of a file named - * "xyzzy" to toggle debugging. Just cd to an NFS-mounted - * filesystem and type 'ls xyzzy' to turn on debugging. - */ - -#if 0 -#define NFS_PROC_DEBUG -#endif +#define NFS_NEED_XDR_TYPES #include <linux/param.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/malloc.h> -#include <linux/nfs_fs.h> #include <linux/utsname.h> #include <linux/errno.h> #include <linux/string.h> #include <linux/in.h> #include <linux/pagemap.h> +#include <linux/sunrpc/clnt.h> +#include <linux/nfs_fs.h> -#include <asm/uaccess.h> - -#ifdef NFS_PROC_DEBUG - -static int proc_debug = 0; -#define PRINTK(format, args...) \ - do { \ - if (proc_debug) \ - printk(format , ## args); \ - } while (0) - -#else /* !NFS_PROC_DEBUG */ - -#define PRINTK(format, args...) do ; while (0) - -#endif /* !NFS_PROC_DEBUG */ - -/* Mapping from NFS error code to "errno" error code. */ -#define errno_NFSERR_IO EIO - -static int *nfs_rpc_header(int *p, int procedure, int ruid); -static int *nfs_rpc_verify(int *p); -static int nfs_stat_to_errno(int stat); - -/* - * Our memory allocation and release functions. - */ - -#define NFS_SLACK_SPACE 1024 /* Total overkill */ -/* !!! Be careful, this constant is now also used in sock.c... - We should easily convert to not using it anymore for most cases... */ - -static inline int *nfs_rpc_alloc(int size) -{ - int *i; - - while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_NFS))) { - schedule(); - } - return i; -} - -static inline void nfs_rpc_free(int *p) -{ - kfree((void *)p); -} +#include <asm/segment.h> /* - * Here are a bunch of xdr encode/decode functions that convert - * between machine dependent and xdr data formats. + * If NFS_DEBUG is defined, you can toggle NFS debugging by causing + * a lookup of "xyzzy". Just cd to an NFS-mounted filesystem and type + * 'ls xyzzy' to turn on debugging. */ +#ifdef NFS_DEBUG +# define NFSDBG_FACILITY NFSDBG_PROC +#endif -#define QUADLEN(len) (((len) + 3) >> 2) - -static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle) -{ - *((struct nfs_fh *) p) = *fhandle; - return p + QUADLEN(sizeof(*fhandle)); -} - -static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle) -{ - *fhandle = *((struct nfs_fh *) p); - return p + QUADLEN(sizeof(*fhandle)); -} - -static inline int *xdr_encode_string(int *p, const char *string) -{ - int len = strlen(string); - int quadlen = QUADLEN(len); - - p[quadlen] = 0; - *p++ = htonl(len); - memcpy(p, string, len); - return p + quadlen; -} - -static inline int *xdr_decode_string(int *p, char *string, unsigned int maxlen) -{ - unsigned int len = ntohl(*p++); - if (len > maxlen) - return NULL; - memcpy(string, p, len); - string[len] = '\0'; - return p + QUADLEN(len); -} - -static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len, - unsigned int maxlen) -{ - *len = ntohl(*p++); - if (*len > maxlen) - return NULL; - *string = (char *) p; - return p + QUADLEN(*len); -} - - -static inline int *xdr_encode_data(int *p, const char *data, int len) -{ - int quadlen = QUADLEN(len); - - p[quadlen] = 0; - *p++ = htonl(len); - copy_from_user(p, data, len); - return p + quadlen; -} - -static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen) -{ - unsigned len = *lenp = ntohl(*p++); - if (len > maxlen) - return NULL; - memcpy(data, p, len); - return p + QUADLEN(len); -} - -static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr) -{ - fattr->type = (enum nfs_ftype) ntohl(*p++); - fattr->mode = ntohl(*p++); - fattr->nlink = ntohl(*p++); - fattr->uid = ntohl(*p++); - fattr->gid = ntohl(*p++); - fattr->size = ntohl(*p++); - fattr->blocksize = ntohl(*p++); - fattr->rdev = ntohl(*p++); - fattr->blocks = ntohl(*p++); - fattr->fsid = ntohl(*p++); - fattr->fileid = ntohl(*p++); - fattr->atime.seconds = ntohl(*p++); - fattr->atime.useconds = ntohl(*p++); - fattr->mtime.seconds = ntohl(*p++); - fattr->mtime.useconds = ntohl(*p++); - fattr->ctime.seconds = ntohl(*p++); - fattr->ctime.useconds = ntohl(*p++); - return p; -} - -static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr) -{ - *p++ = htonl(sattr->mode); - *p++ = htonl(sattr->uid); - *p++ = htonl(sattr->gid); - *p++ = htonl(sattr->size); - *p++ = htonl(sattr->atime.seconds); - *p++ = htonl(sattr->atime.useconds); - *p++ = htonl(sattr->mtime.seconds); - *p++ = htonl(sattr->mtime.useconds); - return p; -} - -static int *xdr_decode_entry(int *p, struct nfs_entry *entry) -{ - entry->fileid = ntohl(*p++); - if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN))) - return NULL; - entry->cookie = ntohl(*p++); - entry->eof = 0; - return p; -} - -static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res) -{ - res->tsize = ntohl(*p++); - res->bsize = ntohl(*p++); - res->blocks = ntohl(*p++); - res->bfree = ntohl(*p++); - res->bavail = ntohl(*p++); - return p; -} /* * One function for each procedure in the NFS protocol. */ - -int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) +int +nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) { - int *p, *p0; - int status; - int ruid = 0; + int status; - PRINTK("NFS call getattr\n"); - if (!(p0 = nfs_rpc_alloc(server->rsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid); - p = xdr_encode_fhandle(p, fhandle); - if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fattr(p, fattr); - PRINTK("NFS reply getattr\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply getattr failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call getattr\n"); + status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0); + dprintk("NFS reply getattr\n"); return status; } -int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_sattr *sattr, struct nfs_fattr *fattr) +int +nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_sattr *sattr, struct nfs_fattr *fattr) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_sattrargs arg = { fhandle, sattr }; + int status; - PRINTK("NFS call setattr\n"); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid); - p = xdr_encode_fhandle(p, fhandle); - p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fattr(p, fattr); - PRINTK("NFS reply setattr\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply setattr failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call setattr\n"); + status = rpc_call(server->client, NFSPROC_SETATTR, &arg, fattr, 0); + dprintk("NFS reply setattr\n"); return status; } -int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, +int +nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_diropargs arg = { dir, name }; + struct nfs_diropok res = { fhandle, fattr }; + int status; - PRINTK("NFS call lookup %s\n", name); -#ifdef NFS_PROC_DEBUG + dprintk("NFS call lookup %s\n", name); +#ifdef RPC_DEBUG if (!strcmp(name, "xyzzy")) - proc_debug = 1 - proc_debug; + nfs_debug = ~nfs_debug; #endif - if (!(p0 = nfs_rpc_alloc(server->rsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fhandle(p, fhandle); - p = xdr_decode_fattr(p, fattr); - PRINTK("NFS reply lookup\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply lookup failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0); + dprintk("NFS reply lookup: %d\n", status); return status; } -int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, - int **p0, char **string, unsigned int *len, unsigned int maxlen) +int +nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, + void **p0, char **string, unsigned int *len, + unsigned int maxlen) { - int *p; - int status, ruid = 0; + struct nfs_readlinkres res = { string, len, maxlen, NULL }; + int status; - PRINTK("NFS call readlink\n"); - if (!(*p0 = nfs_rpc_alloc(server->rsize))) - return -EIO; -retry: - p = nfs_rpc_header(*p0, NFSPROC_READLINK, ruid); - p = xdr_encode_fhandle(p, fhandle); - if ((status = nfs_rpc_call(server, *p0, p, server->rsize)) < 0) - return status; - if (!(p = nfs_rpc_verify(*p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - if (!(p = xdr_decode_string2(p, string, len, maxlen))) { - printk("nfs_proc_readlink: giant pathname\n"); - status = -errno_NFSERR_IO; - } - else /* status = 0, */ - PRINTK("NFS reply readlink\n"); - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply readlink failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } + dprintk("NFS call readlink\n"); + status = rpc_call(server->client, NFSPROC_READLINK, fhandle, &res, 0); + dprintk("NFS reply readlink: %d\n", status); + if (!status) + *p0 = res.buffer; + else if (res.buffer) + kfree(res.buffer); return status; } -int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, - int offset, int count, char *data, struct nfs_fattr *fattr) -{ - int *p, *p0; - int status; - int ruid = 0; - int len; - - PRINTK("NFS call read %d @ %d\n", count, offset); - if (!(p0 = nfs_rpc_alloc(server->rsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_READ, ruid); - p = xdr_encode_fhandle(p, fhandle); - *p++ = htonl(offset); - *p++ = htonl(count); - *p++ = htonl(count); /* traditional, could be any value */ - if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fattr(p, fattr); - if (!(p = xdr_decode_data(p, data, &len, count))) { - printk("nfs_proc_read: giant data size\n"); - status = -errno_NFSERR_IO; - } - else { - status = len; - PRINTK("NFS reply read %d\n", len); - } - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply read failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); +int +nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, int swap, + unsigned long offset, unsigned int count, + void *buffer, struct nfs_fattr *fattr) +{ + struct nfs_readargs arg = { fhandle, offset, count, buffer }; + struct nfs_readres res = { fattr, count }; + int status; + + dprintk("NFS call read %d @ %ld\n", count, offset); + status = rpc_call(server->client, NFSPROC_READ, &arg, &res, + swap? NFS_RPC_SWAPFLAGS : 0); + dprintk("NFS reply read: %d\n", status); return status; } int -nfs_proc_read_request(struct rpc_ioreq *req, struct nfs_server *server, - struct nfs_fh *fh, unsigned long offset, - unsigned long count, __u32 *buf) +nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, int swap, + unsigned long offset, unsigned int count, + const void *buffer, struct nfs_fattr *fattr) { - __u32 *p, *p0; - int len; + struct nfs_writeargs arg = { fhandle, offset, count, buffer }; + int status; - PRINTK("NFS reqst read %ld @ %ld\n", count, offset); - if (!(p0 = nfs_rpc_alloc(NFS_SLACK_SPACE))) - return -EIO; - - p = nfs_rpc_header(p0, NFSPROC_READ, 0); - p = xdr_encode_fhandle(p, fh); - *p++ = htonl(offset); - *p++ = htonl(count); - *p++ = htonl(count); /* traditional, could be any value */ - req->rq_svec[0].iov_base = p0; - req->rq_svec[0].iov_len = (p - p0) << 2; - req->rq_slen = (p - p0) << 2; - req->rq_snr = 1; - - len = (6 + 1 + 17 + 1); /* standard READ reply header */ - req->rq_rvec[0].iov_base = p0; - req->rq_rvec[0].iov_len = len << 2; - req->rq_rvec[1].iov_base = buf; - req->rq_rvec[1].iov_len = count; - req->rq_rvec[2].iov_base = p0 + len; /* spill buffer */ - req->rq_rvec[2].iov_len = (NFS_SLACK_SPACE - len) << 2; - req->rq_rlen = count + NFS_SLACK_SPACE; - req->rq_rnr = 3; - - req->rq_addr = &server->toaddr; - req->rq_alen = sizeof(server->toaddr); - - return rpc_transmit(server->rsock, req); + dprintk("NFS call write %d @ %ld\n", count, offset); + status = rpc_call(server->client, NFSPROC_WRITE, &arg, fattr, + swap? (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) : 0); + dprintk("NFS reply read: %d\n", status); + return status < 0? status : count; } int -nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr) +nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_sattr *sattr, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - int status; - __u32 *p0, *p; - int count; - - p0 = (__u32 *) req->rq_rvec[0].iov_base; + struct nfs_createargs arg = { dir, name, sattr }; + struct nfs_diropok res = { fhandle, fattr }; + int status; - if (!(p = nfs_rpc_verify(p0))) { - /* Tell the upper layers to retry */ - status = -EAGAIN; - /* status = -errno_NFSERR_IO; */ - } else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fattr(p, fattr); - count = ntohl(*p++); - if (p != req->rq_rvec[2].iov_base) { - /* unexpected RPC reply header size. punt. - * fixme: move iovec contents to align data - * on page boundary and adjust RPC header size - * guess. */ - status = -errno_NFSERR_IO; - PRINTK("NFS reply read odd header size %d\n", - (p - p0) << 2); - } else { - status = count; - PRINTK("NFS reply read %d\n", count); - } - } - else { - PRINTK("NFS reply read failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); - return status; -} - -int nfs_proc_write(struct inode * inode, int offset, - int count, const char *data, struct nfs_fattr *fattr) -{ - int *p, *p0; - int status; - int ruid = 0; - void * kdata; /* address of kernel copy */ - struct nfs_server * server = NFS_SERVER(inode); - struct nfs_fh *fhandle = NFS_FH(inode); - - PRINTK("NFS call write %d @ %d\n", count, offset); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid); - p = xdr_encode_fhandle(p, fhandle); - *p++ = htonl(offset); /* traditional, could be any value */ - *p++ = htonl(offset); - *p++ = htonl(count); /* traditional, could be any value */ - kdata = (void *) (p+1); /* start of data in RPC buffer */ - p = xdr_encode_data(p, data, count); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - update_vm_cache(inode, offset, kdata, count); - p = xdr_decode_fattr(p, fattr); - PRINTK("NFS reply write\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply write failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call create %s\n", name); + status = rpc_call(server->client, NFSPROC_CREATE, &arg, &res, 0); + dprintk("NFS reply create: %d\n", status); return status; } -int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, - const char *name, struct nfs_sattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) -{ - int *p, *p0; - int status; - int ruid = 0; - - PRINTK("NFS call create %s\n", name); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fhandle(p, fhandle); - p = xdr_decode_fattr(p, fattr); - PRINTK("NFS reply create\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply create failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); - return status; -} - -int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name) -{ - int *p, *p0; - int status; - int ruid = 0; - - PRINTK("NFS call remove %s\n", name); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - PRINTK("NFS reply remove\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply remove failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); - return status; -} - -int nfs_proc_rename(struct nfs_server *server, - struct nfs_fh *old_dir, const char *old_name, - struct nfs_fh *new_dir, const char *new_name, - int must_be_dir) -{ - int *p, *p0; - int status; - int ruid = 0; - - /* - * Disallow "rename()" with trailing slashes over NFS: getting - * POSIX.1 behaviour is just too unlikely. - */ - if (must_be_dir) - return -EINVAL; - PRINTK("NFS call rename %s -> %s\n", old_name, new_name); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid); - p = xdr_encode_fhandle(p, old_dir); - p = xdr_encode_string(p, old_name); - p = xdr_encode_fhandle(p, new_dir); - p = xdr_encode_string(p, new_name); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - PRINTK("NFS reply rename\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply rename failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); - return status; -} - -int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fh *dir, const char *name) +int +nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_diropargs arg = { dir, name }; + int status; - PRINTK("NFS call link %s\n", name); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_LINK, ruid); - p = xdr_encode_fhandle(p, fhandle); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - PRINTK("NFS reply link\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply link failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call remove %s\n", name); + status = rpc_call(server->client, NFSPROC_REMOVE, &arg, NULL, 0); + dprintk("NFS reply remove: %d\n", status); return status; } -int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, - const char *name, const char *path, struct nfs_sattr *sattr) +int +nfs_proc_rename(struct nfs_server *server, + struct nfs_fh *old_dir, const char *old_name, + struct nfs_fh *new_dir, const char *new_name) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_renameargs arg = { old_dir, old_name, new_dir, new_name }; + int status; - PRINTK("NFS call symlink %s -> %s\n", name, path); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - p = xdr_encode_string(p, path); - p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - PRINTK("NFS reply symlink\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply symlink failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call rename %s -> %s\n", old_name, new_name); + status = rpc_call(server->client, NFSPROC_RENAME, &arg, NULL, 0); + dprintk("NFS reply rename: %d\n", status); return status; } -int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, - const char *name, struct nfs_sattr *sattr, - struct nfs_fh *fhandle, struct nfs_fattr *fattr) +int +nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fh *dir, const char *name) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_linkargs arg = { fhandle, dir, name }; + int status; - PRINTK("NFS call mkdir %s\n", name); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - p = xdr_encode_sattr(p, sattr); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fhandle(p, fhandle); - p = xdr_decode_fattr(p, fattr); - PRINTK("NFS reply mkdir\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply mkdir failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call link %s\n", name); + status = rpc_call(server->client, NFSPROC_LINK, &arg, NULL, 0); + dprintk("NFS reply link: %d\n", status); return status; } -int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name) +int +nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, + const char *name, const char *path, + struct nfs_sattr *sattr) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_symlinkargs arg = { dir, name, path, sattr }; + int status; - PRINTK("NFS call rmdir %s\n", name); - if (!(p0 = nfs_rpc_alloc(server->wsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid); - p = xdr_encode_fhandle(p, dir); - p = xdr_encode_string(p, name); - if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - PRINTK("NFS reply rmdir\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply rmdir failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call symlink %s -> %s\n", name, path); + status = rpc_call(server->client, NFSPROC_SYMLINK, &arg, NULL, 0); + dprintk("NFS reply symlink: %d\n", status); return status; } -int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, - int cookie, int count, struct nfs_entry *entry) +int +nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_sattr *sattr, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - int *p, *p0; - int status; - int ruid = 0; - int i; - int size; - int eof; + struct nfs_createargs arg = { dir, name, sattr }; + struct nfs_diropok res = { fhandle, fattr }; + int status; - PRINTK("NFS call readdir %d @ %d\n", count, cookie); - size = server->rsize; - if (!(p0 = nfs_rpc_alloc(server->rsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid); - p = xdr_encode_fhandle(p, fhandle); - *p++ = htonl(cookie); - *p++ = htonl(size); - if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - for (i = 0; i < count && *p++; i++) { - if (!(p = xdr_decode_entry(p, entry++))) - break; - } - if (!p) { - printk("nfs_proc_readdir: giant filename\n"); - status = -errno_NFSERR_IO; - } - else { - eof = (i == count && !*p++ && *p++) - || (i < count && *p++); - if (eof && i) - entry[-1].eof = 1; - PRINTK("NFS reply readdir %d %s\n", i, - eof ? "eof" : ""); - status = i; - } - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply readdir failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call mkdir %s\n", name); + status = rpc_call(server->client, NFSPROC_MKDIR, &arg, &res, 0); + dprintk("NFS reply mkdir: %d\n", status); return status; } -int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *res) +int +nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name) { - int *p, *p0; - int status; - int ruid = 0; + struct nfs_diropargs arg = { dir, name }; + int status; - PRINTK("NFS call statfs\n"); - if (!(p0 = nfs_rpc_alloc(server->rsize))) - return -EIO; -retry: - p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid); - p = xdr_encode_fhandle(p, fhandle); - if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) { - nfs_rpc_free(p0); - return status; - } - if (!(p = nfs_rpc_verify(p0))) - status = -errno_NFSERR_IO; - else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fsinfo(p, res); - PRINTK("NFS reply statfs\n"); - /* status = 0; */ - } - else { - if (!ruid && current->fsuid == 0 && current->uid != 0) { - ruid = 1; - goto retry; - } - PRINTK("NFS reply statfs failed = %d\n", status); - status = -nfs_stat_to_errno(status); - } - nfs_rpc_free(p0); + dprintk("NFS call rmdir %s\n", name); + status = rpc_call(server->client, NFSPROC_RMDIR, &arg, NULL, 0); + dprintk("NFS reply rmdir: %d\n", status); return status; } /* - * Here are a few RPC-assist functions. + * The READDIR implementation is somewhat hackish - we pass a temporary + * buffer to the encode function, which installs it in the receive + * iovec. The dirent buffer itself is passed in the result struct. */ - -int *rpc_header(int *p, int procedure, int program, int version, - int uid, int gid, - int ngroup, gid_t *groups) -{ - int *p1; - static int xid = 0; - unsigned char *sys = (unsigned char *) system_utsname.nodename; - - if (xid == 0) { - xid = CURRENT_TIME; - xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0]; - } - *p++ = htonl(++xid); - *p++ = htonl(RPC_CALL); - *p++ = htonl(RPC_VERSION); - *p++ = htonl(program); - *p++ = htonl(version); - *p++ = htonl(procedure); - *p++ = htonl(RPC_AUTH_UNIX); - p1 = p++; - *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */ - p = xdr_encode_string(p, (char *) sys); - *p++ = htonl(uid); - *p++ = htonl(gid); - if (ngroup > 16) - ngroup = 16; - *p++ = htonl(ngroup); - while (ngroup) { - *p++ = htonl(*groups); - groups++; - ngroup--; - } - *p1 = htonl((p - (p1 + 1)) << 2); - *p++ = htonl(RPC_AUTH_NULL); - *p++ = htonl(0); - return p; -} - - -static int *nfs_rpc_header(int *p, int procedure, int ruid) -{ - return rpc_header(p, procedure, NFS_PROGRAM, NFS_VERSION, - (ruid ? current->uid : current->fsuid), - current->egid, current->ngroups, current->groups); -} - - -int *rpc_verify(int *p) +int +nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, + u32 cookie, unsigned int size, struct nfs_entry *entry) { - unsigned int n; + struct nfs_readdirargs arg; + struct nfs_readdirres res; + void * buffer; + int status; - p++; - if ((n = ntohl(*p++)) != RPC_REPLY) { - printk("nfs_rpc_verify: not an RPC reply: %x\n", n); - return NULL; - } - if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { - printk("nfs_rpc_verify: RPC call rejected: %d\n", n); - return NULL; - } - switch (n = ntohl(*p++)) { - case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT: - break; - default: - printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n); - return NULL; - } - if ((n = ntohl(*p++)) > 400) { - printk("nfs_rpc_verify: giant auth size\n"); - return NULL; - } - p += QUADLEN(n); - if ((n = ntohl(*p++)) != RPC_SUCCESS) { - printk("nfs_rpc_verify: RPC call failed: %d\n", n); - return NULL; + /* First get a temp buffer for the readdir reply */ + while (!(buffer = (void *) get_free_page(GFP_USER))) { + need_resched = 1; + schedule(); + if (signalled()) + return -ERESTARTSYS; } - return p; -} + arg.fh = fhandle; + arg.cookie = cookie; + arg.buffer = buffer; + arg.bufsiz = server->rsize < PAGE_SIZE? server->rsize : PAGE_SIZE; + res.buffer = entry; + res.bufsiz = size; -static int *nfs_rpc_verify(int *p) -{ - return rpc_verify(p); + dprintk("NFS call readdir %d\n", cookie); + status = rpc_call(server->client, NFSPROC_READDIR, &arg, &res, 0); + dprintk("NFS reply readdir: %d\n", status); + free_page((unsigned long) buffer); + return status; } - -/* - * We need to translate between nfs status return values and - * the local errno values which may not be the same. - */ - -static struct { - int stat; - int errno; -} nfs_errtbl[] = { - { NFS_OK, 0 }, - { NFSERR_PERM, EPERM }, - { NFSERR_NOENT, ENOENT }, - { NFSERR_IO, errno_NFSERR_IO }, - { NFSERR_NXIO, ENXIO }, - { NFSERR_EAGAIN, EAGAIN }, - { NFSERR_ACCES, EACCES }, - { NFSERR_EXIST, EEXIST }, - { NFSERR_NODEV, ENODEV }, - { NFSERR_NOTDIR, ENOTDIR }, - { NFSERR_ISDIR, EISDIR }, - { NFSERR_INVAL, EINVAL }, - { NFSERR_FBIG, EFBIG }, - { NFSERR_NOSPC, ENOSPC }, - { NFSERR_ROFS, EROFS }, - { NFSERR_NAMETOOLONG, ENAMETOOLONG }, - { NFSERR_NOTEMPTY, ENOTEMPTY }, - { NFSERR_DQUOT, EDQUOT }, - { NFSERR_STALE, ESTALE }, -#ifdef EWFLUSH - { NFSERR_WFLUSH, EWFLUSH }, -#endif - { -1, EIO } -}; - -static int nfs_stat_to_errno(int stat) +int +nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *info) { - int i; + int status; - for (i = 0; nfs_errtbl[i].stat != -1; i++) { - if (nfs_errtbl[i].stat == stat) - return nfs_errtbl[i].errno; - } - printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat); - return nfs_errtbl[i].errno; + dprintk("NFS call statfs\n"); + status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0); + dprintk("NFS reply statfs: %d\n", status); + return status; } - |