]> err.no Git - linux-2.6/blobdiff - fs/nfsd/nfs3xdr.c
Merge branch 'audit.b32' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/audit...
[linux-2.6] / fs / nfsd / nfs3xdr.c
index e0e134d6baba0013af5918f0dd0a4f9c3405b246..247d518248bf71b2a95b5ce04b460374dd88c51f 100644 (file)
@@ -154,37 +154,34 @@ decode_sattr3(u32 *p, struct iattr *iap)
 }
 
 static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+             struct kstat *stat)
 {
-       struct vfsmount *mnt = fhp->fh_export->ex_mnt;
        struct dentry   *dentry = fhp->fh_dentry;
-       struct kstat stat;
        struct timespec time;
 
-       vfs_getattr(mnt, dentry, &stat);
-
-       *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
-       *p++ = htonl((u32) stat.mode);
-       *p++ = htonl((u32) stat.nlink);
-       *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
-       *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
-       if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
+       *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
+       *p++ = htonl((u32) stat->mode);
+       *p++ = htonl((u32) stat->nlink);
+       *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
+       *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
+       if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
                p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
        } else {
-               p = xdr_encode_hyper(p, (u64) stat.size);
+               p = xdr_encode_hyper(p, (u64) stat->size);
        }
-       p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9);
-       *p++ = htonl((u32) MAJOR(stat.rdev));
-       *p++ = htonl((u32) MINOR(stat.rdev));
+       p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
+       *p++ = htonl((u32) MAJOR(stat->rdev));
+       *p++ = htonl((u32) MINOR(stat->rdev));
        if (is_fsid(fhp, rqstp->rq_reffh))
                p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
        else
-               p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat.dev));
-       p = xdr_encode_hyper(p, (u64) stat.ino);
-       p = encode_time3(p, &stat.atime);
+               p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev));
+       p = xdr_encode_hyper(p, (u64) stat->ino);
+       p = encode_time3(p, &stat->atime);
        lease_get_mtime(dentry->d_inode, &time); 
        p = encode_time3(p, &time);
-       p = encode_time3(p, &stat.ctime);
+       p = encode_time3(p, &stat->ctime);
 
        return p;
 }
@@ -232,8 +229,14 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
        struct dentry *dentry = fhp->fh_dentry;
        if (dentry && dentry->d_inode != NULL) {
-               *p++ = xdr_one;         /* attributes follow */
-               return encode_fattr3(rqstp, p, fhp);
+               int err;
+               struct kstat stat;
+
+               err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
+               if (!err) {
+                       *p++ = xdr_one;         /* attributes follow */
+                       return encode_fattr3(rqstp, p, fhp, &stat);
+               }
        }
        *p++ = xdr_zero;
        return p;
@@ -327,6 +330,7 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
 {
        unsigned int len;
        int v,pn;
+       u32 max_blocksize = svc_max_payload(rqstp);
 
        if (!(p = decode_fh(p, &args->fh))
         || !(p = xdr_decode_hyper(p, &args->offset)))
@@ -334,17 +338,16 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
 
        len = args->count = ntohl(*p++);
 
-       if (len > NFSSVC_MAXBLKSIZE)
-               len = NFSSVC_MAXBLKSIZE;
+       if (len > max_blocksize)
+               len = max_blocksize;
 
        /* set up the kvec */
        v=0;
        while (len > 0) {
-               pn = rqstp->rq_resused;
-               svc_take_page(rqstp);
-               args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
-               args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
-               len -= args->vec[v].iov_len;
+               pn = rqstp->rq_resused++;
+               rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+               rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
+               len -= rqstp->rq_vec[v].iov_len;
                v++;
        }
        args->vlen = v;
@@ -356,6 +359,7 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
                                        struct nfsd3_writeargs *args)
 {
        unsigned int len, v, hdr;
+       u32 max_blocksize = svc_max_payload(rqstp);
 
        if (!(p = decode_fh(p, &args->fh))
         || !(p = xdr_decode_hyper(p, &args->offset)))
@@ -366,25 +370,26 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
        len = args->len = ntohl(*p++);
 
        hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
-       if (rqstp->rq_arg.len < len + hdr)
+       if (rqstp->rq_arg.len < hdr ||
+           rqstp->rq_arg.len - hdr < len)
                return 0;
 
-       args->vec[0].iov_base = (void*)p;
-       args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+       rqstp->rq_vec[0].iov_base = (void*)p;
+       rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
 
-       if (len > NFSSVC_MAXBLKSIZE)
-               len = NFSSVC_MAXBLKSIZE;
+       if (len > max_blocksize)
+               len = max_blocksize;
        v=  0;
-       while (len > args->vec[v].iov_len) {
-               len -= args->vec[v].iov_len;
+       while (len > rqstp->rq_vec[v].iov_len) {
+               len -= rqstp->rq_vec[v].iov_len;
                v++;
-               args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
-               args->vec[v].iov_len = PAGE_SIZE;
+               rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+               rqstp->rq_vec[v].iov_len = PAGE_SIZE;
        }
-       args->vec[v].iov_len = len;
+       rqstp->rq_vec[v].iov_len = len;
        args->vlen = v+1;
 
-       return args->count == args->len && args->vec[0].iov_len > 0;
+       return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
 }
 
 int
@@ -442,11 +447,11 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
         * This page appears in the rq_res.pages list, but as pages_len is always
         * 0, it won't get in the way
         */
-       svc_take_page(rqstp);
        len = ntohl(*p++);
        if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
                return 0;
-       args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+       args->tname = new =
+               page_address(rqstp->rq_respages[rqstp->rq_resused++]);
        args->tlen = len;
        /* first copy and check from the first page */
        old = (char*)p;
@@ -518,8 +523,8 @@ nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
 {
        if (!(p = decode_fh(p, &args->fh)))
                return 0;
-       svc_take_page(rqstp);
-       args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+       args->buffer =
+               page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -550,8 +555,8 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
        if (args->count > PAGE_SIZE)
                args->count = PAGE_SIZE;
 
-       svc_take_page(rqstp);
-       args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+       args->buffer =
+               page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 
        return xdr_argsize_check(rqstp, p);
 }
@@ -561,6 +566,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
                                        struct nfsd3_readdirargs *args)
 {
        int len, pn;
+       u32 max_blocksize = svc_max_payload(rqstp);
 
        if (!(p = decode_fh(p, &args->fh)))
                return 0;
@@ -569,13 +575,12 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
        args->dircount = ntohl(*p++);
        args->count    = ntohl(*p++);
 
-       len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE :
+       len = (args->count > max_blocksize) ? max_blocksize :
                                                  args->count;
        args->count = len;
 
        while (len > 0) {
-               pn = rqstp->rq_resused;
-               svc_take_page(rqstp);
+               pn = rqstp->rq_resused++;
                if (!args->buffer)
                        args->buffer = page_address(rqstp->rq_respages[pn]);
                len -= PAGE_SIZE;
@@ -615,7 +620,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
                                        struct nfsd3_attrstat *resp)
 {
        if (resp->status == 0)
-               p = encode_fattr3(rqstp, p, &resp->fh);
+               p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
        return xdr_ressize_check(rqstp, p);
 }
 
@@ -664,7 +669,6 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
                rqstp->rq_res.page_len = resp->len;
                if (resp->len & 3) {
                        /* need to pad the tail */
-                       rqstp->rq_restailpage = 0;
                        rqstp->rq_res.tail[0].iov_base = p;
                        *p = 0;
                        rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -689,7 +693,6 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
                rqstp->rq_res.page_len = resp->count;
                if (resp->count & 3) {
                        /* need to pad the tail */
-                       rqstp->rq_restailpage = 0;
                        rqstp->rq_res.tail[0].iov_base = p;
                        *p = 0;
                        rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
@@ -764,7 +767,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
                rqstp->rq_res.page_len = (resp->count) << 2;
 
                /* add the 'tail' to the end of the 'head' page - page 0. */
-               rqstp->rq_restailpage = 0;
                rqstp->rq_res.tail[0].iov_base = p;
                *p++ = 0;               /* no more entries */
                *p++ = htonl(resp->common.err == nfserr_eof);