patch-2.1.32 linux/fs/nfs/proc.c
Next file: linux/fs/nfs/read.c
Previous file: linux/fs/nfs/nfsroot.c
Back to the patch index
Back to the overall index
- Lines: 1203
- Date:
Fri Apr 4 11:05:59 1997
- Orig file:
v2.1.31/linux/fs/nfs/proc.c
- Orig date:
Fri Nov 22 02:33:29 1996
diff -u --recursive --new-file v2.1.31/linux/fs/nfs/proc.c linux/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;
-
- 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);
+ int status;
+
+ 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;
-
- 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);
+ struct nfs_sattrargs arg = { fhandle, sattr };
+ int status;
+
+ 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;
-
- 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);
- }
- return status;
-}
+ struct nfs_readlinkres res = { string, len, maxlen, NULL };
+ int 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);
+ 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_request(struct rpc_ioreq *req, struct nfs_server *server,
- struct nfs_fh *fh, unsigned long offset,
- unsigned long count, __u32 *buf)
-{
- __u32 *p, *p0;
- int len;
-
- 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);
-}
-
-int
-nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr)
-{
- int status;
- __u32 *p0, *p;
- int count;
-
- p0 = (__u32 *) req->rq_rvec[0].iov_base;
-
- 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);
+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_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);
- return status;
+int
+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)
+{
+ struct nfs_writeargs arg = { fhandle, offset, count, buffer };
+ int status;
+
+ 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_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);
+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)
+{
+ struct nfs_createargs arg = { dir, name, sattr };
+ struct nfs_diropok res = { fhandle, fattr };
+ int status;
+
+ 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_remove(struct nfs_server *server, 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;
-
- 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;
-}
+ struct nfs_diropargs arg = { dir, name };
+ int 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);
+ 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_link(struct nfs_server *server, struct nfs_fh *fhandle,
- struct nfs_fh *dir, const char *name)
-{
- int *p, *p0;
- int status;
- int ruid = 0;
-
- 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);
+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)
+{
+ struct nfs_renameargs arg = { old_dir, old_name, new_dir, new_name };
+ int status;
+
+ 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_symlink(struct nfs_server *server, struct nfs_fh *dir,
- const char *name, const char *path, struct nfs_sattr *sattr)
+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;
-
- 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);
- return status;
-}
+ struct nfs_linkargs arg = { fhandle, dir, name };
+ int 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 *p, *p0;
- int status;
- int ruid = 0;
-
- 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 *p, *p0;
- int status;
- int ruid = 0;
-
- 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);
+int
+nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, const char *path,
+ struct nfs_sattr *sattr)
+{
+ struct nfs_symlinkargs arg = { dir, name, path, sattr };
+ int status;
+
+ 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 *p, *p0;
- int status;
- int ruid = 0;
- int i;
- int size;
- int eof;
-
- 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);
+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)
+{
+ struct nfs_createargs arg = { dir, name, sattr };
+ struct nfs_diropok res = { fhandle, fattr };
+ int status;
+
+ 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;
-
- 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);
+ struct nfs_diropargs arg = { dir, name };
+ int status;
+
+ 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;
-
- 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;
+ struct nfs_readdirargs arg;
+ struct nfs_readdirres res;
+ void * buffer;
+ int status;
+
+ /* 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;
-}
-
-static int *nfs_rpc_verify(int *p)
-{
- return rpc_verify(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;
+
+ 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;
}
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov