Commit a334de28665b14f0a33df82699fa9a78cfeedf31

Authored by David Shaw
Committed by Linus Torvalds
1 parent 93fbf1a5de

[PATCH] knfsd: check error status from vfs_getattr and i_op->fsync

Both vfs_getattr and i_op->fsync return error statuses which nfsd was
largely ignoring.  This as noticed when exporting directories using fuse.

This patch cleans up most of the offences, which involves moving the call
to vfs_getattr out of the xdr encoding routines (where it is too late to
report an error) into the main NFS procedure handling routines.

There is still a called to vfs_gettattr (related to the ACL code) where the
status is ignored, and called to nfsd_sync_dir don't check return status
either.

Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 6 changed files with 75 additions and 55 deletions Side-by-side Diff

... ... @@ -56,13 +56,20 @@
56 56 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
57 57 struct nfsd3_attrstat *resp)
58 58 {
59   - int nfserr;
  59 + int err, nfserr;
60 60  
61 61 dprintk("nfsd: GETATTR(3) %s\n",
62   - SVCFH_fmt(&argp->fh));
  62 + SVCFH_fmt(&argp->fh));
63 63  
64 64 fh_copy(&resp->fh, &argp->fh);
65 65 nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
  66 + if (nfserr)
  67 + RETURN_STATUS(nfserr);
  68 +
  69 + err = vfs_getattr(resp->fh.fh_export->ex_mnt,
  70 + resp->fh.fh_dentry, &resp->stat);
  71 + nfserr = nfserrno(err);
  72 +
66 73 RETURN_STATUS(nfserr);
67 74 }
68 75  
... ... @@ -154,37 +154,34 @@
154 154 }
155 155  
156 156 static inline u32 *
157   -encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  157 +encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
  158 + struct kstat *stat)
158 159 {
159   - struct vfsmount *mnt = fhp->fh_export->ex_mnt;
160 160 struct dentry *dentry = fhp->fh_dentry;
161   - struct kstat stat;
162 161 struct timespec time;
163 162  
164   - vfs_getattr(mnt, dentry, &stat);
165   -
166   - *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]);
167   - *p++ = htonl((u32) stat.mode);
168   - *p++ = htonl((u32) stat.nlink);
169   - *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
170   - *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
171   - if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) {
  163 + *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
  164 + *p++ = htonl((u32) stat->mode);
  165 + *p++ = htonl((u32) stat->nlink);
  166 + *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
  167 + *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
  168 + if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
172 169 p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
173 170 } else {
174   - p = xdr_encode_hyper(p, (u64) stat.size);
  171 + p = xdr_encode_hyper(p, (u64) stat->size);
175 172 }
176   - p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9);
177   - *p++ = htonl((u32) MAJOR(stat.rdev));
178   - *p++ = htonl((u32) MINOR(stat.rdev));
  173 + p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
  174 + *p++ = htonl((u32) MAJOR(stat->rdev));
  175 + *p++ = htonl((u32) MINOR(stat->rdev));
179 176 if (is_fsid(fhp, rqstp->rq_reffh))
180 177 p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
181 178 else
182   - p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat.dev));
183   - p = xdr_encode_hyper(p, (u64) stat.ino);
184   - p = encode_time3(p, &stat.atime);
  179 + p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat->dev));
  180 + p = xdr_encode_hyper(p, (u64) stat->ino);
  181 + p = encode_time3(p, &stat->atime);
185 182 lease_get_mtime(dentry->d_inode, &time);
186 183 p = encode_time3(p, &time);
187   - p = encode_time3(p, &stat.ctime);
  184 + p = encode_time3(p, &stat->ctime);
188 185  
189 186 return p;
190 187 }
... ... @@ -232,8 +229,14 @@
232 229 {
233 230 struct dentry *dentry = fhp->fh_dentry;
234 231 if (dentry && dentry->d_inode != NULL) {
235   - *p++ = xdr_one; /* attributes follow */
236   - return encode_fattr3(rqstp, p, fhp);
  232 + int err;
  233 + struct kstat stat;
  234 +
  235 + err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);
  236 + if (!err) {
  237 + *p++ = xdr_one; /* attributes follow */
  238 + return encode_fattr3(rqstp, p, fhp, &stat);
  239 + }
237 240 }
238 241 *p++ = xdr_zero;
239 242 return p;
... ... @@ -616,7 +619,7 @@
616 619 struct nfsd3_attrstat *resp)
617 620 {
618 621 if (resp->status == 0)
619   - p = encode_fattr3(rqstp, p, &resp->fh);
  622 + p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
620 623 return xdr_ressize_check(rqstp, p);
621 624 }
622 625  
... ... @@ -152,46 +152,44 @@
152 152 }
153 153  
154 154 static inline u32 *
155   -encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
  155 +encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
  156 + struct kstat *stat)
156 157 {
157   - struct vfsmount *mnt = fhp->fh_export->ex_mnt;
158 158 struct dentry *dentry = fhp->fh_dentry;
159   - struct kstat stat;
160 159 int type;
161 160 struct timespec time;
162 161  
163   - vfs_getattr(mnt, dentry, &stat);
164   - type = (stat.mode & S_IFMT);
  162 + type = (stat->mode & S_IFMT);
165 163  
166 164 *p++ = htonl(nfs_ftypes[type >> 12]);
167   - *p++ = htonl((u32) stat.mode);
168   - *p++ = htonl((u32) stat.nlink);
169   - *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid));
170   - *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid));
  165 + *p++ = htonl((u32) stat->mode);
  166 + *p++ = htonl((u32) stat->nlink);
  167 + *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
  168 + *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
171 169  
172   - if (S_ISLNK(type) && stat.size > NFS_MAXPATHLEN) {
  170 + if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) {
173 171 *p++ = htonl(NFS_MAXPATHLEN);
174 172 } else {
175   - *p++ = htonl((u32) stat.size);
  173 + *p++ = htonl((u32) stat->size);
176 174 }
177   - *p++ = htonl((u32) stat.blksize);
  175 + *p++ = htonl((u32) stat->blksize);
178 176 if (S_ISCHR(type) || S_ISBLK(type))
179   - *p++ = htonl(new_encode_dev(stat.rdev));
  177 + *p++ = htonl(new_encode_dev(stat->rdev));
180 178 else
181 179 *p++ = htonl(0xffffffff);
182   - *p++ = htonl((u32) stat.blocks);
  180 + *p++ = htonl((u32) stat->blocks);
183 181 if (is_fsid(fhp, rqstp->rq_reffh))
184 182 *p++ = htonl((u32) fhp->fh_export->ex_fsid);
185 183 else
186   - *p++ = htonl(new_encode_dev(stat.dev));
187   - *p++ = htonl((u32) stat.ino);
188   - *p++ = htonl((u32) stat.atime.tv_sec);
189   - *p++ = htonl(stat.atime.tv_nsec ? stat.atime.tv_nsec / 1000 : 0);
  184 + *p++ = htonl(new_encode_dev(stat->dev));
  185 + *p++ = htonl((u32) stat->ino);
  186 + *p++ = htonl((u32) stat->atime.tv_sec);
  187 + *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0);
190 188 lease_get_mtime(dentry->d_inode, &time);
191 189 *p++ = htonl((u32) time.tv_sec);
192 190 *p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0);
193   - *p++ = htonl((u32) stat.ctime.tv_sec);
194   - *p++ = htonl(stat.ctime.tv_nsec ? stat.ctime.tv_nsec / 1000 : 0);
  191 + *p++ = htonl((u32) stat->ctime.tv_sec);
  192 + *p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0);
195 193  
196 194 return p;
197 195 }
... ... @@ -199,7 +197,9 @@
199 197 /* Helper function for NFSv2 ACL code */
200 198 u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
201 199 {
202   - return encode_fattr(rqstp, p, fhp);
  200 + struct kstat stat;
  201 + vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat);
  202 + return encode_fattr(rqstp, p, fhp, &stat);
203 203 }
204 204  
205 205 /*
... ... @@ -394,7 +394,7 @@
394 394 nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
395 395 struct nfsd_attrstat *resp)
396 396 {
397   - p = encode_fattr(rqstp, p, &resp->fh);
  397 + p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
398 398 return xdr_ressize_check(rqstp, p);
399 399 }
400 400  
... ... @@ -403,7 +403,7 @@
403 403 struct nfsd_diropres *resp)
404 404 {
405 405 p = encode_fh(p, &resp->fh);
406   - p = encode_fattr(rqstp, p, &resp->fh);
  406 + p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
407 407 return xdr_ressize_check(rqstp, p);
408 408 }
409 409  
... ... @@ -428,7 +428,7 @@
428 428 nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
429 429 struct nfsd_readres *resp)
430 430 {
431   - p = encode_fattr(rqstp, p, &resp->fh);
  431 + p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
432 432 *p++ = htonl(resp->count);
433 433 xdr_ressize_check(rqstp, p);
434 434  
... ... @@ -717,27 +717,33 @@
717 717 * As this calls fsync (not fdatasync) there is no need for a write_inode
718 718 * after it.
719 719 */
720   -static inline void nfsd_dosync(struct file *filp, struct dentry *dp,
721   - struct file_operations *fop)
  720 +static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
  721 + struct file_operations *fop)
722 722 {
723 723 struct inode *inode = dp->d_inode;
724 724 int (*fsync) (struct file *, struct dentry *, int);
  725 + int err = nfs_ok;
725 726  
726 727 filemap_fdatawrite(inode->i_mapping);
727 728 if (fop && (fsync = fop->fsync))
728   - fsync(filp, dp, 0);
  729 + err=fsync(filp, dp, 0);
729 730 filemap_fdatawait(inode->i_mapping);
  731 +
  732 + return nfserrno(err);
730 733 }
731 734  
732 735  
733   -static void
  736 +static int
734 737 nfsd_sync(struct file *filp)
735 738 {
  739 + int err;
736 740 struct inode *inode = filp->f_dentry->d_inode;
737 741 dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
738 742 down(&inode->i_sem);
739   - nfsd_dosync(filp, filp->f_dentry, filp->f_op);
  743 + err=nfsd_dosync(filp, filp->f_dentry, filp->f_op);
740 744 up(&inode->i_sem);
  745 +
  746 + return err;
741 747 }
742 748  
743 749 void
... ... @@ -962,7 +968,7 @@
962 968  
963 969 if (inode->i_state & I_DIRTY) {
964 970 dprintk("nfsd: write sync %d\n", current->pid);
965   - nfsd_sync(file);
  971 + err=nfsd_sync(file);
966 972 }
967 973 #if 0
968 974 wake_up(&inode->i_wait);
... ... @@ -1066,7 +1072,7 @@
1066 1072 return err;
1067 1073 if (EX_ISSYNC(fhp->fh_export)) {
1068 1074 if (file->f_op && file->f_op->fsync) {
1069   - nfsd_sync(file);
  1075 + err = nfsd_sync(file);
1070 1076 } else {
1071 1077 err = nfserr_notsupp;
1072 1078 }
include/linux/nfsd/xdr.h
... ... @@ -88,10 +88,12 @@
88 88  
89 89 struct nfsd_attrstat {
90 90 struct svc_fh fh;
  91 + struct kstat stat;
91 92 };
92 93  
93 94 struct nfsd_diropres {
94 95 struct svc_fh fh;
  96 + struct kstat stat;
95 97 };
96 98  
97 99 struct nfsd_readlinkres {
... ... @@ -101,6 +103,7 @@
101 103 struct nfsd_readres {
102 104 struct svc_fh fh;
103 105 unsigned long count;
  106 + struct kstat stat;
104 107 };
105 108  
106 109 struct nfsd_readdirres {
include/linux/nfsd/xdr3.h
... ... @@ -126,6 +126,7 @@
126 126 struct nfsd3_attrstat {
127 127 __u32 status;
128 128 struct svc_fh fh;
  129 + struct kstat stat;
129 130 };
130 131  
131 132 /* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */