diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 78376b6c0236..ab93fcfef254 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -366,8 +366,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
366 | } | 366 | } |
367 | 367 | ||
368 | /* Revoke setuid/setgid on chown */ | 368 | /* Revoke setuid/setgid on chown */ |
369 | if (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) || | 369 | if (!S_ISDIR(inode->i_mode) && |
370 | ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid)) { | 370 | (((iap->ia_valid & ATTR_UID) && iap->ia_uid != inode->i_uid) || |
371 | ((iap->ia_valid & ATTR_GID) && iap->ia_gid != inode->i_gid))) { | ||
371 | iap->ia_valid |= ATTR_KILL_PRIV; | 372 | iap->ia_valid |= ATTR_KILL_PRIV; |
372 | if (iap->ia_valid & ATTR_MODE) { | 373 | if (iap->ia_valid & ATTR_MODE) { |
373 | /* we're setting mode too, just clear the s*id bits */ | 374 | /* we're setting mode too, just clear the s*id bits */ |
@@ -960,7 +961,7 @@ static void kill_suid(struct dentry *dentry) | |||
960 | static __be32 | 961 | static __be32 |
961 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 962 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
962 | loff_t offset, struct kvec *vec, int vlen, | 963 | loff_t offset, struct kvec *vec, int vlen, |
963 | unsigned long cnt, int *stablep) | 964 | unsigned long *cnt, int *stablep) |
964 | { | 965 | { |
965 | struct svc_export *exp; | 966 | struct svc_export *exp; |
966 | struct dentry *dentry; | 967 | struct dentry *dentry; |
@@ -974,7 +975,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
974 | err = nfserr_perm; | 975 | err = nfserr_perm; |
975 | 976 | ||
976 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 977 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
977 | (!lock_may_write(file->f_path.dentry->d_inode, offset, cnt))) | 978 | (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt))) |
978 | goto out; | 979 | goto out; |
979 | #endif | 980 | #endif |
980 | 981 | ||
@@ -1009,7 +1010,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1009 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); | 1010 | host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset); |
1010 | set_fs(oldfs); | 1011 | set_fs(oldfs); |
1011 | if (host_err >= 0) { | 1012 | if (host_err >= 0) { |
1012 | nfsdstats.io_write += cnt; | 1013 | nfsdstats.io_write += host_err; |
1013 | fsnotify_modify(file->f_path.dentry); | 1014 | fsnotify_modify(file->f_path.dentry); |
1014 | } | 1015 | } |
1015 | 1016 | ||
@@ -1054,9 +1055,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1054 | } | 1055 | } |
1055 | 1056 | ||
1056 | dprintk("nfsd: write complete host_err=%d\n", host_err); | 1057 | dprintk("nfsd: write complete host_err=%d\n", host_err); |
1057 | if (host_err >= 0) | 1058 | if (host_err >= 0) { |
1058 | err = 0; | 1059 | err = 0; |
1059 | else | 1060 | *cnt = host_err; |
1061 | } else | ||
1060 | err = nfserrno(host_err); | 1062 | err = nfserrno(host_err); |
1061 | out: | 1063 | out: |
1062 | return err; | 1064 | return err; |
@@ -1098,7 +1100,7 @@ out: | |||
1098 | */ | 1100 | */ |
1099 | __be32 | 1101 | __be32 |
1100 | nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 1102 | nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
1101 | loff_t offset, struct kvec *vec, int vlen, unsigned long cnt, | 1103 | loff_t offset, struct kvec *vec, int vlen, unsigned long *cnt, |
1102 | int *stablep) | 1104 | int *stablep) |
1103 | { | 1105 | { |
1104 | __be32 err = 0; | 1106 | __be32 err = 0; |
@@ -1179,6 +1181,21 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, | |||
1179 | return 0; | 1181 | return 0; |
1180 | } | 1182 | } |
1181 | 1183 | ||
1184 | /* HPUX client sometimes creates a file in mode 000, and sets size to 0. | ||
1185 | * setting size to 0 may fail for some specific file systems by the permission | ||
1186 | * checking which requires WRITE permission but the mode is 000. | ||
1187 | * we ignore the resizing(to 0) on the just new created file, since the size is | ||
1188 | * 0 after file created. | ||
1189 | * | ||
1190 | * call this only after vfs_create() is called. | ||
1191 | * */ | ||
1192 | static void | ||
1193 | nfsd_check_ignore_resizing(struct iattr *iap) | ||
1194 | { | ||
1195 | if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) | ||
1196 | iap->ia_valid &= ~ATTR_SIZE; | ||
1197 | } | ||
1198 | |||
1182 | /* | 1199 | /* |
1183 | * Create a file (regular, directory, device, fifo); UNIX sockets | 1200 | * Create a file (regular, directory, device, fifo); UNIX sockets |
1184 | * not yet implemented. | 1201 | * not yet implemented. |
@@ -1274,6 +1291,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1274 | switch (type) { | 1291 | switch (type) { |
1275 | case S_IFREG: | 1292 | case S_IFREG: |
1276 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); | 1293 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); |
1294 | if (!host_err) | ||
1295 | nfsd_check_ignore_resizing(iap); | ||
1277 | break; | 1296 | break; |
1278 | case S_IFDIR: | 1297 | case S_IFDIR: |
1279 | host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); | 1298 | host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); |
@@ -1427,6 +1446,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1427 | /* setattr will sync the child (or not) */ | 1446 | /* setattr will sync the child (or not) */ |
1428 | } | 1447 | } |
1429 | 1448 | ||
1449 | nfsd_check_ignore_resizing(iap); | ||
1450 | |||
1430 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1451 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
1431 | /* Cram the verifier into atime/mtime */ | 1452 | /* Cram the verifier into atime/mtime */ |
1432 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME | 1453 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME |