diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /fs/nfs/proc.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'fs/nfs/proc.c')
-rw-r--r-- | fs/nfs/proc.c | 166 |
1 files changed, 134 insertions, 32 deletions
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index 9aeb66751..ff71bd631 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -33,10 +33,6 @@ #define NFS_PROC_DEBUG #endif -#ifdef MODULE -#include <linux/module.h> -#endif - #include <linux/param.h> #include <linux/sched.h> #include <linux/mm.h> @@ -46,7 +42,9 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/in.h> -#include <asm/segment.h> +#include <linux/pagemap.h> + +#include <asm/uaccess.h> #ifdef NFS_PROC_DEBUG @@ -144,26 +142,22 @@ static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len, } -static inline int *xdr_encode_data(int *p, char *data, int len) +static inline int *xdr_encode_data(int *p, const char *data, int len) { int quadlen = QUADLEN(len); p[quadlen] = 0; *p++ = htonl(len); - memcpy_fromfs(p, data, len); + copy_from_user(p, data, len); return p + quadlen; } -static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen, - int fs) +static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen) { unsigned len = *lenp = ntohl(*p++); if (len > maxlen) return NULL; - if (fs) - memcpy_tofs(data, p, len); - else - memcpy(data, p, len); + memcpy(data, p, len); return p + QUADLEN(len); } @@ -377,7 +371,7 @@ retry: } int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, - int offset, int count, char *data, struct nfs_fattr *fattr, int fs) + int offset, int count, char *data, struct nfs_fattr *fattr) { int *p, *p0; int status; @@ -401,7 +395,7 @@ retry: 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, fs))) { + if (!(p = xdr_decode_data(p, data, &len, count))) { printk("nfs_proc_read: giant data size\n"); status = -errno_NFSERR_IO; } @@ -422,12 +416,90 @@ retry: return status; } -int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, - int offset, int count, char *data, struct nfs_fattr *fattr) +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); + 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))) @@ -438,6 +510,7 @@ retry: *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); @@ -446,6 +519,7 @@ retry: 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; */ @@ -539,12 +613,19 @@ retry: 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_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; @@ -822,10 +903,11 @@ retry: * Here are a few RPC-assist functions. */ -static int *nfs_rpc_header(int *p, int procedure, int ruid) +int *rpc_header(int *p, int procedure, int program, int version, + int uid, int gid, + int ngroup, gid_t *groups) { - int *p1, *p2; - int i; + int *p1; static int xid = 0; unsigned char *sys = (unsigned char *) system_utsname.nodename; @@ -836,32 +918,45 @@ static int *nfs_rpc_header(int *p, int procedure, int ruid) *p++ = htonl(++xid); *p++ = htonl(RPC_CALL); *p++ = htonl(RPC_VERSION); - *p++ = htonl(NFS_PROGRAM); - *p++ = htonl(NFS_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(ruid ? current->uid : current->fsuid); - *p++ = htonl(current->egid); - p2 = p++; - for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++) - *p++ = htonl(current->groups[i]); - *p2 = htonl(i); + *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_verify(int *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) { unsigned int n; p++; if ((n = ntohl(*p++)) != RPC_REPLY) { - printk("nfs_rpc_verify: not an RPC reply: %d\n", n); + printk("nfs_rpc_verify: not an RPC reply: %x\n", n); return NULL; } if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { @@ -886,7 +981,14 @@ static int *nfs_rpc_verify(int *p) } return p; } - + + +static int *nfs_rpc_verify(int *p) +{ + return rpc_verify(p); +} + + /* * We need to translate between nfs status return values and * the local errno values which may not be the same. |