OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [nfs/] [proc.c] - Diff between revs 1628 and 1765

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 1628 Rev 1765
/*
/*
 *  linux/fs/nfs/proc.c
 *  linux/fs/nfs/proc.c
 *
 *
 *  Copyright (C) 1992, 1993, 1994  Rick Sladkey
 *  Copyright (C) 1992, 1993, 1994  Rick Sladkey
 *
 *
 *  OS-independent nfs remote procedure call functions
 *  OS-independent nfs remote procedure call functions
 *
 *
 *  Tuned by Alan Cox <A.Cox@swansea.ac.uk> for >3K buffers
 *  Tuned by Alan Cox <A.Cox@swansea.ac.uk> for >3K buffers
 *  so at last we can have decent(ish) throughput off a
 *  so at last we can have decent(ish) throughput off a
 *  Sun server.
 *  Sun server.
 *
 *
 *  Coding optimized and cleaned up by Florian La Roche.
 *  Coding optimized and cleaned up by Florian La Roche.
 *  Note: Error returns are optimized for NFS_OK, which isn't translated via
 *  Note: Error returns are optimized for NFS_OK, which isn't translated via
 *  nfs_stat_to_errno(), but happens to be already the right return code.
 *  nfs_stat_to_errno(), but happens to be already the right return code.
 *
 *
 *  FixMe: We ought to define a sensible small max size for
 *  FixMe: We ought to define a sensible small max size for
 *  things like getattr that are tiny packets and use the
 *  things like getattr that are tiny packets and use the
 *  old get_free_page stuff with it.
 *  old get_free_page stuff with it.
 *
 *
 *  Also, the code currently doesn't check the size of the packet, when
 *  Also, the code currently doesn't check the size of the packet, when
 *  it decodes the packet.
 *  it decodes the packet.
 *
 *
 *  Feel free to fix it and mail me the diffs if it worries you.
 *  Feel free to fix it and mail me the diffs if it worries you.
 */
 */
 
 
/*
/*
 * Fixes:
 * Fixes:
 *    Ion Badulescu <ionut@cs.columbia.edu>     : FIFO's need special handling in NFSv2
 *    Ion Badulescu <ionut@cs.columbia.edu>     : FIFO's need special handling in NFSv2
 */
 */
 
 
/*
/*
 * Defining NFS_PROC_DEBUG causes a lookup of a file named
 * Defining NFS_PROC_DEBUG causes a lookup of a file named
 * "xyzzy" to toggle debugging.  Just cd to an NFS-mounted
 * "xyzzy" to toggle debugging.  Just cd to an NFS-mounted
 * filesystem and type 'ls xyzzy' to turn on debugging.
 * filesystem and type 'ls xyzzy' to turn on debugging.
 */
 */
 
 
#if 0
#if 0
#define NFS_PROC_DEBUG
#define NFS_PROC_DEBUG
#endif
#endif
 
 
#include <linux/param.h>
#include <linux/param.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/malloc.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs.h>
#include <linux/utsname.h>
#include <linux/utsname.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/pagemap.h>
#include <linux/pagemap.h>
 
 
#include <asm/segment.h>
#include <asm/segment.h>
 
 
#ifdef NFS_PROC_DEBUG
#ifdef NFS_PROC_DEBUG
 
 
static int proc_debug = 0;
static int proc_debug = 0;
#define PRINTK(format, args...) \
#define PRINTK(format, args...) \
        do {                                            \
        do {                                            \
                if (proc_debug)                         \
                if (proc_debug)                         \
                        printk(format , ## args);       \
                        printk(format , ## args);       \
        } while (0)
        } while (0)
 
 
#else /* !NFS_PROC_DEBUG */
#else /* !NFS_PROC_DEBUG */
 
 
#define PRINTK(format, args...) do ; while (0)
#define PRINTK(format, args...) do ; while (0)
 
 
#endif /* !NFS_PROC_DEBUG */
#endif /* !NFS_PROC_DEBUG */
 
 
/* Mapping from NFS error code to "errno" error code. */
/* Mapping from NFS error code to "errno" error code. */
#define errno_NFSERR_IO EIO
#define errno_NFSERR_IO EIO
 
 
static int *nfs_rpc_header(int *p, int procedure, int ruid);
static int *nfs_rpc_header(int *p, int procedure, int ruid);
static int *nfs_rpc_verify(int *p);
static int *nfs_rpc_verify(int *p);
static int nfs_stat_to_errno(int stat);
static int nfs_stat_to_errno(int stat);
 
 
/*
/*
 * Our memory allocation and release functions.
 * Our memory allocation and release functions.
 */
 */
 
 
#define NFS_SLACK_SPACE         1024    /* Total overkill */ 
#define NFS_SLACK_SPACE         1024    /* Total overkill */ 
/* !!! Be careful, this constant is now also used in sock.c...
/* !!! Be careful, this constant is now also used in sock.c...
   We should easily convert to not using it anymore for most cases... */
   We should easily convert to not using it anymore for most cases... */
 
 
static inline int *nfs_rpc_alloc(int size)
static inline int *nfs_rpc_alloc(int size)
{
{
        int *i;
        int *i;
 
 
        while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_NFS))) {
        while (!(i = (int *)kmalloc(size+NFS_SLACK_SPACE,GFP_NFS))) {
                schedule();
                schedule();
        }
        }
        return i;
        return i;
}
}
 
 
static inline void nfs_rpc_free(int *p)
static inline void nfs_rpc_free(int *p)
{
{
        kfree((void *)p);
        kfree((void *)p);
}
}
 
 
/*
/*
 * Here are a bunch of xdr encode/decode functions that convert
 * Here are a bunch of xdr encode/decode functions that convert
 * between machine dependent and xdr data formats.
 * between machine dependent and xdr data formats.
 */
 */
 
 
#define QUADLEN(len) (((len) + 3) >> 2)
#define QUADLEN(len) (((len) + 3) >> 2)
 
 
static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle)
static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle)
{
{
        *((struct nfs_fh *) p) = *fhandle;
        *((struct nfs_fh *) p) = *fhandle;
        return p + QUADLEN(sizeof(*fhandle));
        return p + QUADLEN(sizeof(*fhandle));
}
}
 
 
static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle)
static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle)
{
{
        *fhandle = *((struct nfs_fh *) p);
        *fhandle = *((struct nfs_fh *) p);
        return p + QUADLEN(sizeof(*fhandle));
        return p + QUADLEN(sizeof(*fhandle));
}
}
 
 
static inline int *xdr_encode_string(int *p, const char *string)
static inline int *xdr_encode_string(int *p, const char *string)
{
{
        int len = strlen(string);
        int len = strlen(string);
        int quadlen = QUADLEN(len);
        int quadlen = QUADLEN(len);
 
 
        p[quadlen] = 0;
        p[quadlen] = 0;
        *p++ = htonl(len);
        *p++ = htonl(len);
        memcpy(p, string, len);
        memcpy(p, string, len);
        return p + quadlen;
        return p + quadlen;
}
}
 
 
static inline int *xdr_decode_string(int *p, char *string, unsigned int maxlen)
static inline int *xdr_decode_string(int *p, char *string, unsigned int maxlen)
{
{
        unsigned int len = ntohl(*p++);
        unsigned int len = ntohl(*p++);
        if (len > maxlen)
        if (len > maxlen)
                return NULL;
                return NULL;
        memcpy(string, p, len);
        memcpy(string, p, len);
        string[len] = '\0';
        string[len] = '\0';
        return p + QUADLEN(len);
        return p + QUADLEN(len);
}
}
 
 
static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len,
static inline int *xdr_decode_string2(int *p, char **string, unsigned int *len,
                        unsigned int maxlen)
                        unsigned int maxlen)
{
{
        *len = ntohl(*p++);
        *len = ntohl(*p++);
        if (*len > maxlen)
        if (*len > maxlen)
                return NULL;
                return NULL;
        *string = (char *) p;
        *string = (char *) p;
        return p + QUADLEN(*len);
        return p + QUADLEN(*len);
}
}
 
 
 
 
static inline int *xdr_encode_data(int *p, const char *data, int len)
static inline int *xdr_encode_data(int *p, const char *data, int len)
{
{
        int quadlen = QUADLEN(len);
        int quadlen = QUADLEN(len);
 
 
        p[quadlen] = 0;
        p[quadlen] = 0;
        *p++ = htonl(len);
        *p++ = htonl(len);
        memcpy_fromfs(p, data, len);
        memcpy_fromfs(p, data, len);
        return p + quadlen;
        return p + quadlen;
}
}
 
 
static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
{
{
        unsigned len = *lenp = ntohl(*p++);
        unsigned len = *lenp = ntohl(*p++);
        if (len > maxlen)
        if (len > maxlen)
                return NULL;
                return NULL;
        memcpy(data, p, len);
        memcpy(data, p, len);
        return p + QUADLEN(len);
        return p + QUADLEN(len);
}
}
 
 
static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr)
static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr)
{
{
        fattr->type = (enum nfs_ftype) ntohl(*p++);
        fattr->type = (enum nfs_ftype) ntohl(*p++);
        fattr->mode = ntohl(*p++);
        fattr->mode = ntohl(*p++);
        fattr->nlink = ntohl(*p++);
        fattr->nlink = ntohl(*p++);
        fattr->uid = ntohl(*p++);
        fattr->uid = ntohl(*p++);
        fattr->gid = ntohl(*p++);
        fattr->gid = ntohl(*p++);
        fattr->size = ntohl(*p++);
        fattr->size = ntohl(*p++);
        fattr->blocksize = ntohl(*p++);
        fattr->blocksize = ntohl(*p++);
        fattr->rdev = ntohl(*p++);
        fattr->rdev = ntohl(*p++);
        fattr->blocks = ntohl(*p++);
        fattr->blocks = ntohl(*p++);
        fattr->fsid = ntohl(*p++);
        fattr->fsid = ntohl(*p++);
        fattr->fileid = ntohl(*p++);
        fattr->fileid = ntohl(*p++);
        fattr->atime.seconds = ntohl(*p++);
        fattr->atime.seconds = ntohl(*p++);
        fattr->atime.useconds = ntohl(*p++);
        fattr->atime.useconds = ntohl(*p++);
        fattr->mtime.seconds = ntohl(*p++);
        fattr->mtime.seconds = ntohl(*p++);
        fattr->mtime.useconds = ntohl(*p++);
        fattr->mtime.useconds = ntohl(*p++);
        fattr->ctime.seconds = ntohl(*p++);
        fattr->ctime.seconds = ntohl(*p++);
        fattr->ctime.useconds = ntohl(*p++);
        fattr->ctime.useconds = ntohl(*p++);
        if (fattr->type == NFCHR && fattr->rdev == NFS_FIFO_DEV) {
        if (fattr->type == NFCHR && fattr->rdev == NFS_FIFO_DEV) {
                fattr->type = NFFIFO;
                fattr->type = NFFIFO;
                fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
                fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
                fattr->rdev = 0;
                fattr->rdev = 0;
        }
        }
        return p;
        return p;
}
}
 
 
static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr)
static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr)
{
{
        *p++ = htonl(sattr->mode);
        *p++ = htonl(sattr->mode);
        *p++ = htonl(sattr->uid);
        *p++ = htonl(sattr->uid);
        *p++ = htonl(sattr->gid);
        *p++ = htonl(sattr->gid);
        *p++ = htonl(sattr->size);
        *p++ = htonl(sattr->size);
        *p++ = htonl(sattr->atime.seconds);
        *p++ = htonl(sattr->atime.seconds);
        *p++ = htonl(sattr->atime.useconds);
        *p++ = htonl(sattr->atime.useconds);
        *p++ = htonl(sattr->mtime.seconds);
        *p++ = htonl(sattr->mtime.seconds);
        *p++ = htonl(sattr->mtime.useconds);
        *p++ = htonl(sattr->mtime.useconds);
        return p;
        return p;
}
}
 
 
static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
{
{
        entry->fileid = ntohl(*p++);
        entry->fileid = ntohl(*p++);
        if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN)))
        if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN)))
                return NULL;
                return NULL;
        entry->cookie = ntohl(*p++);
        entry->cookie = ntohl(*p++);
        entry->eof = 0;
        entry->eof = 0;
        return p;
        return p;
}
}
 
 
static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res)
static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res)
{
{
        res->tsize = ntohl(*p++);
        res->tsize = ntohl(*p++);
        res->bsize = ntohl(*p++);
        res->bsize = ntohl(*p++);
        res->blocks = ntohl(*p++);
        res->blocks = ntohl(*p++);
        res->bfree = ntohl(*p++);
        res->bfree = ntohl(*p++);
        res->bavail = ntohl(*p++);
        res->bavail = ntohl(*p++);
        return p;
        return p;
}
}
 
 
/*
/*
 * One function for each procedure in the NFS protocol.
 * One function for each procedure in the NFS protocol.
 */
 */
 
 
int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                     struct nfs_fattr *fattr)
                     struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  getattr\n");
        PRINTK("NFS call  getattr\n");
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
        p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                PRINTK("NFS reply getattr\n");
                PRINTK("NFS reply getattr\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply getattr failed = %d\n", status);
                PRINTK("NFS reply getattr failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
                     struct nfs_sattr *sattr, struct nfs_fattr *fattr)
                     struct nfs_sattr *sattr, struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  setattr\n");
        PRINTK("NFS call  setattr\n");
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
        p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_sattr(p, sattr);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                PRINTK("NFS reply setattr\n");
                PRINTK("NFS reply setattr\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply setattr failed = %d\n", status);
                PRINTK("NFS reply setattr failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        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)
                    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  lookup %s\n", name);
        PRINTK("NFS call  lookup %s\n", name);
#ifdef NFS_PROC_DEBUG
#ifdef NFS_PROC_DEBUG
        if (!strcmp(name, "xyzzy"))
        if (!strcmp(name, "xyzzy"))
                proc_debug = 1 - proc_debug;
                proc_debug = 1 - proc_debug;
#endif
#endif
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
        p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fhandle(p, fhandle);
                p = xdr_decode_fhandle(p, fhandle);
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                PRINTK("NFS reply lookup\n");
                PRINTK("NFS reply lookup\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply lookup failed = %d\n", status);
                PRINTK("NFS reply lookup failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
                int **p0, char **string, unsigned int *len, unsigned int maxlen)
                int **p0, char **string, unsigned int *len, unsigned int maxlen)
{
{
        int *p;
        int *p;
        int status, ruid = 0;
        int status, ruid = 0;
 
 
        PRINTK("NFS call  readlink\n");
        PRINTK("NFS call  readlink\n");
        if (!(*p0 = nfs_rpc_alloc(server->rsize)))
        if (!(*p0 = nfs_rpc_alloc(server->rsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(*p0, NFSPROC_READLINK, ruid);
        p = nfs_rpc_header(*p0, NFSPROC_READLINK, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        if ((status = nfs_rpc_call(server, *p0, p, server->rsize)) < 0)
        if ((status = nfs_rpc_call(server, *p0, p, server->rsize)) < 0)
                return status;
                return status;
        if (!(p = nfs_rpc_verify(*p0)))
        if (!(p = nfs_rpc_verify(*p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                if (!(p = xdr_decode_string2(p, string, len, maxlen))) {
                if (!(p = xdr_decode_string2(p, string, len, maxlen))) {
                        printk("nfs_proc_readlink: giant pathname\n");
                        printk("nfs_proc_readlink: giant pathname\n");
                        status = -errno_NFSERR_IO;
                        status = -errno_NFSERR_IO;
                }
                }
                else    /* status = 0, */
                else    /* status = 0, */
                        PRINTK("NFS reply readlink\n");
                        PRINTK("NFS reply readlink\n");
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply readlink failed = %d\n", status);
                PRINTK("NFS reply readlink failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        return status;
        return status;
}
}
 
 
int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
          int offset, int count, char *data, struct nfs_fattr *fattr)
          int offset, int count, char *data, struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
        int len;
        int len;
 
 
        PRINTK("NFS call  read %d @ %d\n", count, offset);
        PRINTK("NFS call  read %d @ %d\n", count, offset);
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_READ, ruid);
        p = nfs_rpc_header(p0, NFSPROC_READ, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        *p++ = htonl(offset);
        *p++ = htonl(offset);
        *p++ = htonl(count);
        *p++ = htonl(count);
        *p++ = htonl(count); /* traditional, could be any value */
        *p++ = htonl(count); /* traditional, could be any value */
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                if (!(p = xdr_decode_data(p, data, &len, count))) {
                if (!(p = xdr_decode_data(p, data, &len, count))) {
                        printk("nfs_proc_read: giant data size\n");
                        printk("nfs_proc_read: giant data size\n");
                        status = -errno_NFSERR_IO;
                        status = -errno_NFSERR_IO;
                }
                }
                else {
                else {
                        status = len;
                        status = len;
                        PRINTK("NFS reply read %d\n", len);
                        PRINTK("NFS reply read %d\n", len);
                }
                }
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply read failed = %d\n", status);
                PRINTK("NFS reply read failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int
int
nfs_proc_read_request(struct rpc_ioreq *req, struct nfs_server *server,
nfs_proc_read_request(struct rpc_ioreq *req, struct nfs_server *server,
                        struct nfs_fh *fh, unsigned long offset,
                        struct nfs_fh *fh, unsigned long offset,
                        unsigned long count, __u32 *buf)
                        unsigned long count, __u32 *buf)
{
{
        __u32   *p, *p0;
        __u32   *p, *p0;
        int     len;
        int     len;
 
 
        PRINTK("NFS reqst read %ld @ %ld\n", count, offset);
        PRINTK("NFS reqst read %ld @ %ld\n", count, offset);
        if (!(p0 = nfs_rpc_alloc(NFS_SLACK_SPACE)))
        if (!(p0 = nfs_rpc_alloc(NFS_SLACK_SPACE)))
                return -EIO;
                return -EIO;
 
 
        p = nfs_rpc_header(p0, NFSPROC_READ, 0);
        p = nfs_rpc_header(p0, NFSPROC_READ, 0);
        p = xdr_encode_fhandle(p, fh);
        p = xdr_encode_fhandle(p, fh);
        *p++ = htonl(offset);
        *p++ = htonl(offset);
        *p++ = htonl(count);
        *p++ = htonl(count);
        *p++ = htonl(count); /* traditional, could be any value */
        *p++ = htonl(count); /* traditional, could be any value */
        req->rq_svec[0].iov_base = p0;
        req->rq_svec[0].iov_base = p0;
        req->rq_svec[0].iov_len  = (p - p0) << 2;
        req->rq_svec[0].iov_len  = (p - p0) << 2;
        req->rq_slen = (p - p0) << 2;
        req->rq_slen = (p - p0) << 2;
        req->rq_snr = 1;
        req->rq_snr = 1;
 
 
        len = (6 + 1 + 17 + 1);         /* standard READ reply header */
        len = (6 + 1 + 17 + 1);         /* standard READ reply header */
        req->rq_rvec[0].iov_base = p0;
        req->rq_rvec[0].iov_base = p0;
        req->rq_rvec[0].iov_len  = len << 2;
        req->rq_rvec[0].iov_len  = len << 2;
        req->rq_rvec[1].iov_base = buf;
        req->rq_rvec[1].iov_base = buf;
        req->rq_rvec[1].iov_len  = count;
        req->rq_rvec[1].iov_len  = count;
        req->rq_rvec[2].iov_base = p0 + len;            /* spill buffer */
        req->rq_rvec[2].iov_base = p0 + len;            /* spill buffer */
        req->rq_rvec[2].iov_len  = (NFS_SLACK_SPACE - len) << 2;
        req->rq_rvec[2].iov_len  = (NFS_SLACK_SPACE - len) << 2;
        req->rq_rlen = count + NFS_SLACK_SPACE;
        req->rq_rlen = count + NFS_SLACK_SPACE;
        req->rq_rnr = 3;
        req->rq_rnr = 3;
 
 
        req->rq_addr = &server->toaddr;
        req->rq_addr = &server->toaddr;
        req->rq_alen = sizeof(server->toaddr);
        req->rq_alen = sizeof(server->toaddr);
 
 
        return rpc_transmit(server->rsock, req);
        return rpc_transmit(server->rsock, req);
}
}
 
 
int
int
nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr)
nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr)
{
{
        int             status;
        int             status;
        __u32           *p0, *p;
        __u32           *p0, *p;
        int             count;
        int             count;
 
 
        p0 = (__u32 *) req->rq_rvec[0].iov_base;
        p0 = (__u32 *) req->rq_rvec[0].iov_base;
 
 
        if (!(p = nfs_rpc_verify(p0))) {
        if (!(p = nfs_rpc_verify(p0))) {
                /* Tell the upper layers to retry */
                /* Tell the upper layers to retry */
                status = -EAGAIN;
                status = -EAGAIN;
                /* status = -errno_NFSERR_IO; */
                /* status = -errno_NFSERR_IO; */
        } else if ((status = ntohl(*p++)) == NFS_OK) {
        } else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                count = ntohl(*p++);
                count = ntohl(*p++);
                if (p != req->rq_rvec[2].iov_base) {
                if (p != req->rq_rvec[2].iov_base) {
                        /* unexpected RPC reply header size. punt.
                        /* unexpected RPC reply header size. punt.
                         * fixme: move iovec contents to align data
                         * fixme: move iovec contents to align data
                         * on page boundary and adjust RPC header size
                         * on page boundary and adjust RPC header size
                         * guess. */
                         * guess. */
                        status = -errno_NFSERR_IO;
                        status = -errno_NFSERR_IO;
                        PRINTK("NFS reply read odd header size %d\n",
                        PRINTK("NFS reply read odd header size %d\n",
                                        (p - p0) << 2);
                                        (p - p0) << 2);
                } else {
                } else {
                        status = count;
                        status = count;
                        PRINTK("NFS reply read %d\n", count);
                        PRINTK("NFS reply read %d\n", count);
                }
                }
        }
        }
        else {
        else {
                PRINTK("NFS reply read failed = %d\n", status);
                PRINTK("NFS reply read failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_write(struct inode * inode, int offset,
int nfs_proc_write(struct inode * inode, int offset,
                   int count, const char *data, struct nfs_fattr *fattr)
                   int count, const char *data, struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
        void * kdata;   /* address of kernel copy */
        void * kdata;   /* address of kernel copy */
        struct nfs_server * server = NFS_SERVER(inode);
        struct nfs_server * server = NFS_SERVER(inode);
        struct nfs_fh *fhandle = NFS_FH(inode);
        struct nfs_fh *fhandle = NFS_FH(inode);
 
 
        PRINTK("NFS call  write %d @ %d\n", count, offset);
        PRINTK("NFS call  write %d @ %d\n", count, offset);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid);
        p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        *p++ = htonl(offset); /* traditional, could be any value */
        *p++ = htonl(offset); /* traditional, could be any value */
        *p++ = htonl(offset);
        *p++ = htonl(offset);
        *p++ = htonl(count); /* traditional, could be any value */
        *p++ = htonl(count); /* traditional, could be any value */
        kdata = (void *) (p+1); /* start of data in RPC buffer */
        kdata = (void *) (p+1); /* start of data in RPC buffer */
        p = xdr_encode_data(p, data, count);
        p = xdr_encode_data(p, data, count);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                update_vm_cache(inode, offset, kdata, count);
                update_vm_cache(inode, offset, kdata, count);
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                PRINTK("NFS reply write\n");
                PRINTK("NFS reply write\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply write failed = %d\n", status);
                PRINTK("NFS reply write failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
                    const char *name, struct nfs_sattr *sattr,
                    const char *name, struct nfs_sattr *sattr,
                    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
                    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  create %s\n", name);
        PRINTK("NFS call  create %s\n", name);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
        p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        p = xdr_encode_sattr(p, sattr);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fhandle(p, fhandle);
                p = xdr_decode_fhandle(p, fhandle);
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                PRINTK("NFS reply create\n");
                PRINTK("NFS reply create\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply create failed = %d\n", status);
                PRINTK("NFS reply create failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return 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 *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  remove %s\n", name);
        PRINTK("NFS call  remove %s\n", name);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
        p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                PRINTK("NFS reply remove\n");
                PRINTK("NFS reply remove\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply remove failed = %d\n", status);
                PRINTK("NFS reply remove failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_rename(struct nfs_server *server,
int nfs_proc_rename(struct nfs_server *server,
                    struct nfs_fh *old_dir, const char *old_name,
                    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 must_be_dir)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        /*
        /*
         * Disallow "rename()" with trailing slashes over NFS: getting
         * Disallow "rename()" with trailing slashes over NFS: getting
         * POSIX.1 behaviour is just too unlikely.
         * POSIX.1 behaviour is just too unlikely.
         */
         */
        if (must_be_dir)
        if (must_be_dir)
                return -EINVAL;
                return -EINVAL;
        PRINTK("NFS call  rename %s -> %s\n", old_name, new_name);
        PRINTK("NFS call  rename %s -> %s\n", old_name, new_name);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
        p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
        p = xdr_encode_fhandle(p, old_dir);
        p = xdr_encode_fhandle(p, old_dir);
        p = xdr_encode_string(p, old_name);
        p = xdr_encode_string(p, old_name);
        p = xdr_encode_fhandle(p, new_dir);
        p = xdr_encode_fhandle(p, new_dir);
        p = xdr_encode_string(p, new_name);
        p = xdr_encode_string(p, new_name);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                PRINTK("NFS reply rename\n");
                PRINTK("NFS reply rename\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply rename failed = %d\n", status);
                PRINTK("NFS reply rename failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
                  struct nfs_fh *dir, const char *name)
                  struct nfs_fh *dir, const char *name)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  link %s\n", name);
        PRINTK("NFS call  link %s\n", name);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_LINK, ruid);
        p = nfs_rpc_header(p0, NFSPROC_LINK, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                PRINTK("NFS reply link\n");
                PRINTK("NFS reply link\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply link failed = %d\n", status);
                PRINTK("NFS reply link failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
                     const char *name, const char *path, struct nfs_sattr *sattr)
                     const char *name, const char *path, struct nfs_sattr *sattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  symlink %s -> %s\n", name, path);
        PRINTK("NFS call  symlink %s -> %s\n", name, path);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
        p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, path);
        p = xdr_encode_string(p, path);
        p = xdr_encode_sattr(p, sattr);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                PRINTK("NFS reply symlink\n");
                PRINTK("NFS reply symlink\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply symlink failed = %d\n", status);
                PRINTK("NFS reply symlink failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
                   const char *name, struct nfs_sattr *sattr,
                   const char *name, struct nfs_sattr *sattr,
                   struct nfs_fh *fhandle, struct nfs_fattr *fattr)
                   struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  mkdir %s\n", name);
        PRINTK("NFS call  mkdir %s\n", name);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid);
        p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        p = xdr_encode_sattr(p, sattr);
        p = xdr_encode_sattr(p, sattr);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fhandle(p, fhandle);
                p = xdr_decode_fhandle(p, fhandle);
                p = xdr_decode_fattr(p, fattr);
                p = xdr_decode_fattr(p, fattr);
                PRINTK("NFS reply mkdir\n");
                PRINTK("NFS reply mkdir\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply mkdir failed = %d\n", status);
                PRINTK("NFS reply mkdir failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  rmdir %s\n", name);
        PRINTK("NFS call  rmdir %s\n", name);
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
        if (!(p0 = nfs_rpc_alloc(server->wsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
        p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_fhandle(p, dir);
        p = xdr_encode_string(p, name);
        p = xdr_encode_string(p, name);
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                PRINTK("NFS reply rmdir\n");
                PRINTK("NFS reply rmdir\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply rmdir failed = %d\n", status);
                PRINTK("NFS reply rmdir failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
                     int cookie, int count, struct nfs_entry *entry)
                     int cookie, int count, struct nfs_entry *entry)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
        int i;
        int i;
        int size;
        int size;
        int eof;
        int eof;
 
 
        PRINTK("NFS call  readdir %d @ %d\n", count, cookie);
        PRINTK("NFS call  readdir %d @ %d\n", count, cookie);
        size = server->rsize;
        size = server->rsize;
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid);
        p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        *p++ = htonl(cookie);
        *p++ = htonl(cookie);
        *p++ = htonl(size);
        *p++ = htonl(size);
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                for (i = 0; i < count && *p++; i++) {
                for (i = 0; i < count && *p++; i++) {
                        if (!(p = xdr_decode_entry(p, entry++)))
                        if (!(p = xdr_decode_entry(p, entry++)))
                                break;
                                break;
                }
                }
                if (!p) {
                if (!p) {
                        printk("nfs_proc_readdir: giant filename\n");
                        printk("nfs_proc_readdir: giant filename\n");
                        status = -errno_NFSERR_IO;
                        status = -errno_NFSERR_IO;
                }
                }
                else {
                else {
                        eof = (i == count && !*p++ && *p++)
                        eof = (i == count && !*p++ && *p++)
                              || (i < count && *p++);
                              || (i < count && *p++);
                        if (eof && i)
                        if (eof && i)
                                entry[-1].eof = 1;
                                entry[-1].eof = 1;
                        PRINTK("NFS reply readdir %d %s\n", i,
                        PRINTK("NFS reply readdir %d %s\n", i,
                               eof ? "eof" : "");
                               eof ? "eof" : "");
                        status = i;
                        status = i;
                }
                }
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply readdir failed = %d\n", status);
                PRINTK("NFS reply readdir failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
                    struct nfs_fsinfo *res)
                    struct nfs_fsinfo *res)
{
{
        int *p, *p0;
        int *p, *p0;
        int status;
        int status;
        int ruid = 0;
        int ruid = 0;
 
 
        PRINTK("NFS call  statfs\n");
        PRINTK("NFS call  statfs\n");
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
        if (!(p0 = nfs_rpc_alloc(server->rsize)))
                return -EIO;
                return -EIO;
retry:
retry:
        p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
        p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
        p = xdr_encode_fhandle(p, fhandle);
        p = xdr_encode_fhandle(p, fhandle);
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
        if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
                nfs_rpc_free(p0);
                nfs_rpc_free(p0);
                return status;
                return status;
        }
        }
        if (!(p = nfs_rpc_verify(p0)))
        if (!(p = nfs_rpc_verify(p0)))
                status = -errno_NFSERR_IO;
                status = -errno_NFSERR_IO;
        else if ((status = ntohl(*p++)) == NFS_OK) {
        else if ((status = ntohl(*p++)) == NFS_OK) {
                p = xdr_decode_fsinfo(p, res);
                p = xdr_decode_fsinfo(p, res);
                PRINTK("NFS reply statfs\n");
                PRINTK("NFS reply statfs\n");
                /* status = 0; */
                /* status = 0; */
        }
        }
        else {
        else {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                if (!ruid && current->fsuid == 0 && current->uid != 0) {
                        ruid = 1;
                        ruid = 1;
                        goto retry;
                        goto retry;
                }
                }
                PRINTK("NFS reply statfs failed = %d\n", status);
                PRINTK("NFS reply statfs failed = %d\n", status);
                status = -nfs_stat_to_errno(status);
                status = -nfs_stat_to_errno(status);
        }
        }
        nfs_rpc_free(p0);
        nfs_rpc_free(p0);
        return status;
        return status;
}
}
 
 
/*
/*
 * Here are a few RPC-assist functions.
 * Here are a few RPC-assist functions.
 */
 */
 
 
int *rpc_header(int *p, int procedure, int program, int version,
int *rpc_header(int *p, int procedure, int program, int version,
                                        int uid, int gid, int *groups)
                                        int uid, int gid, int *groups)
{
{
        int *p1, *p2;
        int *p1, *p2;
        int i;
        int i;
        static int xid = 0;
        static int xid = 0;
        unsigned char *sys = (unsigned char *) system_utsname.nodename;
        unsigned char *sys = (unsigned char *) system_utsname.nodename;
 
 
        if (xid == 0) {
        if (xid == 0) {
                xid = CURRENT_TIME;
                xid = CURRENT_TIME;
                xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0];
                xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0];
        }
        }
        *p++ = htonl(++xid);
        *p++ = htonl(++xid);
        *p++ = htonl(RPC_CALL);
        *p++ = htonl(RPC_CALL);
        *p++ = htonl(RPC_VERSION);
        *p++ = htonl(RPC_VERSION);
        *p++ = htonl(program);
        *p++ = htonl(program);
        *p++ = htonl(version);
        *p++ = htonl(version);
        *p++ = htonl(procedure);
        *p++ = htonl(procedure);
        *p++ = htonl(RPC_AUTH_UNIX);
        *p++ = htonl(RPC_AUTH_UNIX);
        p1 = p++;
        p1 = p++;
        *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
        *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
        p = xdr_encode_string(p, (char *) sys);
        p = xdr_encode_string(p, (char *) sys);
        *p++ = htonl(uid);
        *p++ = htonl(uid);
        *p++ = htonl(gid);
        *p++ = htonl(gid);
        p2 = p++;
        p2 = p++;
        for (i = 0; i < 16 && i < NGROUPS && groups[i] != NOGROUP; i++)
        for (i = 0; i < 16 && i < NGROUPS && groups[i] != NOGROUP; i++)
                *p++ = htonl(groups[i]);
                *p++ = htonl(groups[i]);
        *p2 = htonl(i);
        *p2 = htonl(i);
        *p1 = htonl((p - (p1 + 1)) << 2);
        *p1 = htonl((p - (p1 + 1)) << 2);
        *p++ = htonl(RPC_AUTH_NULL);
        *p++ = htonl(RPC_AUTH_NULL);
        *p++ = htonl(0);
        *p++ = htonl(0);
        return p;
        return p;
}
}
 
 
 
 
static int *nfs_rpc_header(int *p, int procedure, int ruid)
static int *nfs_rpc_header(int *p, int procedure, int ruid)
{
{
        return rpc_header(p, procedure, NFS_PROGRAM, NFS_VERSION,
        return rpc_header(p, procedure, NFS_PROGRAM, NFS_VERSION,
                        (ruid ? current->uid : current->fsuid),
                        (ruid ? current->uid : current->fsuid),
                        current->egid, current->groups);
                        current->egid, current->groups);
}
}
 
 
 
 
int *rpc_verify(int *p)
int *rpc_verify(int *p)
{
{
        unsigned int n;
        unsigned int n;
 
 
        p++;
        p++;
        if ((n = ntohl(*p++)) != RPC_REPLY) {
        if ((n = ntohl(*p++)) != RPC_REPLY) {
                printk("nfs_rpc_verify: not an RPC reply: %x\n", n);
                printk("nfs_rpc_verify: not an RPC reply: %x\n", n);
                return NULL;
                return NULL;
        }
        }
        if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
        if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
                printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
                printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
                return NULL;
                return NULL;
        }
        }
        switch (n = ntohl(*p++)) {
        switch (n = ntohl(*p++)) {
        case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT:
        case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT:
                break;
                break;
        default:
        default:
                printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n);
                printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n);
                return NULL;
                return NULL;
        }
        }
        if ((n = ntohl(*p++)) > 400) {
        if ((n = ntohl(*p++)) > 400) {
                printk("nfs_rpc_verify: giant auth size\n");
                printk("nfs_rpc_verify: giant auth size\n");
                return NULL;
                return NULL;
        }
        }
        p += QUADLEN(n);
        p += QUADLEN(n);
        if ((n = ntohl(*p++)) != RPC_SUCCESS) {
        if ((n = ntohl(*p++)) != RPC_SUCCESS) {
                printk("nfs_rpc_verify: RPC call failed: %d\n", n);
                printk("nfs_rpc_verify: RPC call failed: %d\n", n);
                return NULL;
                return NULL;
        }
        }
        return p;
        return p;
}
}
 
 
 
 
static int *nfs_rpc_verify(int *p)
static int *nfs_rpc_verify(int *p)
{
{
        return rpc_verify(p);
        return rpc_verify(p);
}
}
 
 
 
 
/*
/*
 * We need to translate between nfs status return values and
 * We need to translate between nfs status return values and
 * the local errno values which may not be the same.
 * the local errno values which may not be the same.
 */
 */
 
 
static struct {
static struct {
        int stat;
        int stat;
        int errno;
        int errno;
} nfs_errtbl[] = {
} nfs_errtbl[] = {
        { NFS_OK,               0                },
        { NFS_OK,               0                },
        { NFSERR_PERM,          EPERM           },
        { NFSERR_PERM,          EPERM           },
        { NFSERR_NOENT,         ENOENT          },
        { NFSERR_NOENT,         ENOENT          },
        { NFSERR_IO,            errno_NFSERR_IO },
        { NFSERR_IO,            errno_NFSERR_IO },
        { NFSERR_NXIO,          ENXIO           },
        { NFSERR_NXIO,          ENXIO           },
        { NFSERR_EAGAIN,        EAGAIN          },
        { NFSERR_EAGAIN,        EAGAIN          },
        { NFSERR_ACCES,         EACCES          },
        { NFSERR_ACCES,         EACCES          },
        { NFSERR_EXIST,         EEXIST          },
        { NFSERR_EXIST,         EEXIST          },
        { NFSERR_XDEV,          EXDEV           },
        { NFSERR_XDEV,          EXDEV           },
        { NFSERR_NODEV,         ENODEV          },
        { NFSERR_NODEV,         ENODEV          },
        { NFSERR_NOTDIR,        ENOTDIR         },
        { NFSERR_NOTDIR,        ENOTDIR         },
        { NFSERR_ISDIR,         EISDIR          },
        { NFSERR_ISDIR,         EISDIR          },
        { NFSERR_INVAL,         EINVAL          },
        { NFSERR_INVAL,         EINVAL          },
        { NFSERR_FBIG,          EFBIG           },
        { NFSERR_FBIG,          EFBIG           },
        { NFSERR_NOSPC,         ENOSPC          },
        { NFSERR_NOSPC,         ENOSPC          },
        { NFSERR_ROFS,          EROFS           },
        { NFSERR_ROFS,          EROFS           },
        { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
        { NFSERR_NAMETOOLONG,   ENAMETOOLONG    },
        { NFSERR_NOTEMPTY,      ENOTEMPTY       },
        { NFSERR_NOTEMPTY,      ENOTEMPTY       },
        { NFSERR_DQUOT,         EDQUOT          },
        { NFSERR_DQUOT,         EDQUOT          },
        { NFSERR_STALE,         ESTALE          },
        { NFSERR_STALE,         ESTALE          },
#ifdef EWFLUSH
#ifdef EWFLUSH
        { NFSERR_WFLUSH,        EWFLUSH         },
        { NFSERR_WFLUSH,        EWFLUSH         },
#endif
#endif
        { -1,                   EIO             }
        { -1,                   EIO             }
};
};
 
 
static int nfs_stat_to_errno(int stat)
static int nfs_stat_to_errno(int stat)
{
{
        int i;
        int i;
 
 
        for (i = 0; nfs_errtbl[i].stat != -1; i++) {
        for (i = 0; nfs_errtbl[i].stat != -1; i++) {
                if (nfs_errtbl[i].stat == stat)
                if (nfs_errtbl[i].stat == stat)
                        return nfs_errtbl[i].errno;
                        return nfs_errtbl[i].errno;
        }
        }
        printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
        printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
        return nfs_errtbl[i].errno;
        return nfs_errtbl[i].errno;
}
}
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.