diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
| -rw-r--r-- | fs/nfsd/vfs.c | 161 | 
1 files changed, 75 insertions, 86 deletions
| diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8715d194561a..a11b0e8678ee 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -20,13 +20,14 @@ | |||
| 20 | #include <linux/fcntl.h> | 20 | #include <linux/fcntl.h> | 
| 21 | #include <linux/namei.h> | 21 | #include <linux/namei.h> | 
| 22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> | 
| 23 | #include <linux/quotaops.h> | ||
| 24 | #include <linux/fsnotify.h> | 23 | #include <linux/fsnotify.h> | 
| 25 | #include <linux/posix_acl_xattr.h> | 24 | #include <linux/posix_acl_xattr.h> | 
| 26 | #include <linux/xattr.h> | 25 | #include <linux/xattr.h> | 
| 27 | #include <linux/jhash.h> | 26 | #include <linux/jhash.h> | 
| 28 | #include <linux/ima.h> | 27 | #include <linux/ima.h> | 
| 29 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> | 
| 29 | #include <linux/exportfs.h> | ||
| 30 | #include <linux/writeback.h> | ||
| 30 | 31 | ||
| 31 | #ifdef CONFIG_NFSD_V3 | 32 | #ifdef CONFIG_NFSD_V3 | 
| 32 | #include "xdr3.h" | 33 | #include "xdr3.h" | 
| @@ -271,6 +272,32 @@ out: | |||
| 271 | return err; | 272 | return err; | 
| 272 | } | 273 | } | 
| 273 | 274 | ||
| 275 | /* | ||
| 276 | * Commit metadata changes to stable storage. | ||
| 277 | */ | ||
| 278 | static int | ||
| 279 | commit_metadata(struct svc_fh *fhp) | ||
| 280 | { | ||
| 281 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
| 282 | const struct export_operations *export_ops = inode->i_sb->s_export_op; | ||
| 283 | int error = 0; | ||
| 284 | |||
| 285 | if (!EX_ISSYNC(fhp->fh_export)) | ||
| 286 | return 0; | ||
| 287 | |||
| 288 | if (export_ops->commit_metadata) { | ||
| 289 | error = export_ops->commit_metadata(inode); | ||
| 290 | } else { | ||
| 291 | struct writeback_control wbc = { | ||
| 292 | .sync_mode = WB_SYNC_ALL, | ||
| 293 | .nr_to_write = 0, /* metadata only */ | ||
| 294 | }; | ||
| 295 | |||
| 296 | error = sync_inode(inode, &wbc); | ||
| 297 | } | ||
| 298 | |||
| 299 | return error; | ||
| 300 | } | ||
| 274 | 301 | ||
| 275 | /* | 302 | /* | 
| 276 | * Set various file attributes. | 303 | * Set various file attributes. | 
| @@ -361,7 +388,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
| 361 | * If we are changing the size of the file, then | 388 | * If we are changing the size of the file, then | 
| 362 | * we need to break all leases. | 389 | * we need to break all leases. | 
| 363 | */ | 390 | */ | 
| 364 | host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); | 391 | host_err = break_lease(inode, O_WRONLY | O_NONBLOCK); | 
| 365 | if (host_err == -EWOULDBLOCK) | 392 | if (host_err == -EWOULDBLOCK) | 
| 366 | host_err = -ETIMEDOUT; | 393 | host_err = -ETIMEDOUT; | 
| 367 | if (host_err) /* ENOMEM or EWOULDBLOCK */ | 394 | if (host_err) /* ENOMEM or EWOULDBLOCK */ | 
| @@ -377,7 +404,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
| 377 | put_write_access(inode); | 404 | put_write_access(inode); | 
| 378 | goto out_nfserr; | 405 | goto out_nfserr; | 
| 379 | } | 406 | } | 
| 380 | vfs_dq_init(inode); | ||
| 381 | } | 407 | } | 
| 382 | 408 | ||
| 383 | /* sanitize the mode change */ | 409 | /* sanitize the mode change */ | 
| @@ -734,7 +760,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 734 | * Check to see if there are any leases on this file. | 760 | * Check to see if there are any leases on this file. | 
| 735 | * This may block while leases are broken. | 761 | * This may block while leases are broken. | 
| 736 | */ | 762 | */ | 
| 737 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? FMODE_WRITE : 0)); | 763 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); | 
| 738 | if (host_err == -EWOULDBLOCK) | 764 | if (host_err == -EWOULDBLOCK) | 
| 739 | host_err = -ETIMEDOUT; | 765 | host_err = -ETIMEDOUT; | 
| 740 | if (host_err) /* NOMEM or WOULDBLOCK */ | 766 | if (host_err) /* NOMEM or WOULDBLOCK */ | 
| @@ -745,8 +771,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 745 | flags = O_RDWR|O_LARGEFILE; | 771 | flags = O_RDWR|O_LARGEFILE; | 
| 746 | else | 772 | else | 
| 747 | flags = O_WRONLY|O_LARGEFILE; | 773 | flags = O_WRONLY|O_LARGEFILE; | 
| 748 | |||
| 749 | vfs_dq_init(inode); | ||
| 750 | } | 774 | } | 
| 751 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), | 775 | *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), | 
| 752 | flags, current_cred()); | 776 | flags, current_cred()); | 
| @@ -771,43 +795,6 @@ nfsd_close(struct file *filp) | |||
| 771 | } | 795 | } | 
| 772 | 796 | ||
| 773 | /* | 797 | /* | 
| 774 | * Sync a file | ||
| 775 | * As this calls fsync (not fdatasync) there is no need for a write_inode | ||
| 776 | * after it. | ||
| 777 | */ | ||
| 778 | static inline int nfsd_dosync(struct file *filp, struct dentry *dp, | ||
| 779 | const struct file_operations *fop) | ||
| 780 | { | ||
| 781 | struct inode *inode = dp->d_inode; | ||
| 782 | int (*fsync) (struct file *, struct dentry *, int); | ||
| 783 | int err; | ||
| 784 | |||
| 785 | err = filemap_write_and_wait(inode->i_mapping); | ||
| 786 | if (err == 0 && fop && (fsync = fop->fsync)) | ||
| 787 | err = fsync(filp, dp, 0); | ||
| 788 | return err; | ||
| 789 | } | ||
| 790 | |||
| 791 | static int | ||
| 792 | nfsd_sync(struct file *filp) | ||
| 793 | { | ||
| 794 | int err; | ||
| 795 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 796 | dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name); | ||
| 797 | mutex_lock(&inode->i_mutex); | ||
| 798 | err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op); | ||
| 799 | mutex_unlock(&inode->i_mutex); | ||
| 800 | |||
| 801 | return err; | ||
| 802 | } | ||
| 803 | |||
| 804 | int | ||
| 805 | nfsd_sync_dir(struct dentry *dp) | ||
| 806 | { | ||
| 807 | return nfsd_dosync(NULL, dp, dp->d_inode->i_fop); | ||
| 808 | } | ||
| 809 | |||
| 810 | /* | ||
| 811 | * Obtain the readahead parameters for the file | 798 | * Obtain the readahead parameters for the file | 
| 812 | * specified by (dev, ino). | 799 | * specified by (dev, ino). | 
| 813 | */ | 800 | */ | 
| @@ -1010,7 +997,7 @@ static int wait_for_concurrent_writes(struct file *file) | |||
| 1010 | 997 | ||
| 1011 | if (inode->i_state & I_DIRTY) { | 998 | if (inode->i_state & I_DIRTY) { | 
| 1012 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | 999 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | 
| 1013 | err = nfsd_sync(file); | 1000 | err = vfs_fsync(file, file->f_path.dentry, 0); | 
| 1014 | } | 1001 | } | 
| 1015 | last_ino = inode->i_ino; | 1002 | last_ino = inode->i_ino; | 
| 1016 | last_dev = inode->i_sb->s_dev; | 1003 | last_dev = inode->i_sb->s_dev; | 
| @@ -1158,8 +1145,9 @@ out: | |||
| 1158 | #ifdef CONFIG_NFSD_V3 | 1145 | #ifdef CONFIG_NFSD_V3 | 
| 1159 | /* | 1146 | /* | 
| 1160 | * Commit all pending writes to stable storage. | 1147 | * Commit all pending writes to stable storage. | 
| 1161 | * Strictly speaking, we could sync just the indicated file region here, | 1148 | * | 
| 1162 | * but there's currently no way we can ask the VFS to do so. | 1149 | * Note: we only guarantee that data that lies within the range specified | 
| 1150 | * by the 'offset' and 'count' parameters will be synced. | ||
| 1163 | * | 1151 | * | 
| 1164 | * Unfortunately we cannot lock the file to make sure we return full WCC | 1152 | * Unfortunately we cannot lock the file to make sure we return full WCC | 
| 1165 | * data to the client, as locking happens lower down in the filesystem. | 1153 | * data to the client, as locking happens lower down in the filesystem. | 
| @@ -1169,23 +1157,32 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1169 | loff_t offset, unsigned long count) | 1157 | loff_t offset, unsigned long count) | 
| 1170 | { | 1158 | { | 
| 1171 | struct file *file; | 1159 | struct file *file; | 
| 1172 | __be32 err; | 1160 | loff_t end = LLONG_MAX; | 
| 1161 | __be32 err = nfserr_inval; | ||
| 1173 | 1162 | ||
| 1174 | if ((u64)count > ~(u64)offset) | 1163 | if (offset < 0) | 
| 1175 | return nfserr_inval; | 1164 | goto out; | 
| 1165 | if (count != 0) { | ||
| 1166 | end = offset + (loff_t)count - 1; | ||
| 1167 | if (end < offset) | ||
| 1168 | goto out; | ||
| 1169 | } | ||
| 1176 | 1170 | ||
| 1177 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); | 1171 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); | 
| 1178 | if (err) | 1172 | if (err) | 
| 1179 | return err; | 1173 | goto out; | 
| 1180 | if (EX_ISSYNC(fhp->fh_export)) { | 1174 | if (EX_ISSYNC(fhp->fh_export)) { | 
| 1181 | if (file->f_op && file->f_op->fsync) { | 1175 | int err2 = vfs_fsync_range(file, file->f_path.dentry, | 
| 1182 | err = nfserrno(nfsd_sync(file)); | 1176 | offset, end, 0); | 
| 1183 | } else { | 1177 | |
| 1178 | if (err2 != -EINVAL) | ||
| 1179 | err = nfserrno(err2); | ||
| 1180 | else | ||
| 1184 | err = nfserr_notsupp; | 1181 | err = nfserr_notsupp; | 
| 1185 | } | ||
| 1186 | } | 1182 | } | 
| 1187 | 1183 | ||
| 1188 | nfsd_close(file); | 1184 | nfsd_close(file); | 
| 1185 | out: | ||
| 1189 | return err; | 1186 | return err; | 
| 1190 | } | 1187 | } | 
| 1191 | #endif /* CONFIG_NFSD_V3 */ | 1188 | #endif /* CONFIG_NFSD_V3 */ | 
| @@ -1338,12 +1335,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1338 | goto out_nfserr; | 1335 | goto out_nfserr; | 
| 1339 | } | 1336 | } | 
| 1340 | 1337 | ||
| 1341 | if (EX_ISSYNC(fhp->fh_export)) { | 1338 | err = nfsd_create_setattr(rqstp, resfhp, iap); | 
| 1342 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
| 1343 | write_inode_now(dchild->d_inode, 1); | ||
| 1344 | } | ||
| 1345 | 1339 | ||
| 1346 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1340 | /* | 
| 1341 | * nfsd_setattr already committed the child. Transactional filesystems | ||
| 1342 | * had a chance to commit changes for both parent and child | ||
| 1343 | * simultaneously making the following commit_metadata a noop. | ||
| 1344 | */ | ||
| 1345 | err2 = nfserrno(commit_metadata(fhp)); | ||
| 1347 | if (err2) | 1346 | if (err2) | 
| 1348 | err = err2; | 1347 | err = err2; | 
| 1349 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1348 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 
| @@ -1375,7 +1374,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1375 | struct dentry *dentry, *dchild = NULL; | 1374 | struct dentry *dentry, *dchild = NULL; | 
| 1376 | struct inode *dirp; | 1375 | struct inode *dirp; | 
| 1377 | __be32 err; | 1376 | __be32 err; | 
| 1378 | __be32 err2; | ||
| 1379 | int host_err; | 1377 | int host_err; | 
| 1380 | __u32 v_mtime=0, v_atime=0; | 1378 | __u32 v_mtime=0, v_atime=0; | 
| 1381 | 1379 | ||
| @@ -1470,11 +1468,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1470 | if (created) | 1468 | if (created) | 
| 1471 | *created = 1; | 1469 | *created = 1; | 
| 1472 | 1470 | ||
| 1473 | if (EX_ISSYNC(fhp->fh_export)) { | ||
| 1474 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
| 1475 | /* setattr will sync the child (or not) */ | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | nfsd_check_ignore_resizing(iap); | 1471 | nfsd_check_ignore_resizing(iap); | 
| 1479 | 1472 | ||
| 1480 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1473 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 
| @@ -1489,9 +1482,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1489 | } | 1482 | } | 
| 1490 | 1483 | ||
| 1491 | set_attr: | 1484 | set_attr: | 
| 1492 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1485 | err = nfsd_create_setattr(rqstp, resfhp, iap); | 
| 1493 | if (err2) | 1486 | |
| 1494 | err = err2; | 1487 | /* | 
| 1488 | * nfsd_setattr already committed the child (and possibly also the parent). | ||
| 1489 | */ | ||
| 1490 | if (!err) | ||
| 1491 | err = nfserrno(commit_metadata(fhp)); | ||
| 1495 | 1492 | ||
| 1496 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1493 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 
| 1497 | /* | 1494 | /* | 
| @@ -1606,12 +1603,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1606 | } | 1603 | } | 
| 1607 | } else | 1604 | } else | 
| 1608 | host_err = vfs_symlink(dentry->d_inode, dnew, path); | 1605 | host_err = vfs_symlink(dentry->d_inode, dnew, path); | 
| 1609 | |||
| 1610 | if (!host_err) { | ||
| 1611 | if (EX_ISSYNC(fhp->fh_export)) | ||
| 1612 | host_err = nfsd_sync_dir(dentry); | ||
| 1613 | } | ||
| 1614 | err = nfserrno(host_err); | 1606 | err = nfserrno(host_err); | 
| 1607 | if (!err) | ||
| 1608 | err = nfserrno(commit_metadata(fhp)); | ||
| 1615 | fh_unlock(fhp); | 1609 | fh_unlock(fhp); | 
| 1616 | 1610 | ||
| 1617 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1611 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 
| @@ -1673,11 +1667,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
| 1673 | } | 1667 | } | 
| 1674 | host_err = vfs_link(dold, dirp, dnew); | 1668 | host_err = vfs_link(dold, dirp, dnew); | 
| 1675 | if (!host_err) { | 1669 | if (!host_err) { | 
| 1676 | if (EX_ISSYNC(ffhp->fh_export)) { | 1670 | err = nfserrno(commit_metadata(ffhp)); | 
| 1677 | err = nfserrno(nfsd_sync_dir(ddir)); | 1671 | if (!err) | 
| 1678 | write_inode_now(dest, 1); | 1672 | err = nfserrno(commit_metadata(tfhp)); | 
| 1679 | } | ||
| 1680 | err = 0; | ||
| 1681 | } else { | 1673 | } else { | 
| 1682 | if (host_err == -EXDEV && rqstp->rq_vers == 2) | 1674 | if (host_err == -EXDEV && rqstp->rq_vers == 2) | 
| 1683 | err = nfserr_acces; | 1675 | err = nfserr_acces; | 
| @@ -1773,10 +1765,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
| 1773 | goto out_dput_new; | 1765 | goto out_dput_new; | 
| 1774 | 1766 | ||
| 1775 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1767 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 
| 1776 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { | 1768 | if (!host_err) { | 
| 1777 | host_err = nfsd_sync_dir(tdentry); | 1769 | host_err = commit_metadata(tfhp); | 
| 1778 | if (!host_err) | 1770 | if (!host_err) | 
| 1779 | host_err = nfsd_sync_dir(fdentry); | 1771 | host_err = commit_metadata(ffhp); | 
| 1780 | } | 1772 | } | 
| 1781 | 1773 | ||
| 1782 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1774 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 
| @@ -1857,12 +1849,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 1857 | 1849 | ||
| 1858 | dput(rdentry); | 1850 | dput(rdentry); | 
| 1859 | 1851 | ||
| 1860 | if (host_err) | 1852 | if (!host_err) | 
| 1861 | goto out_drop; | 1853 | host_err = commit_metadata(fhp); | 
| 1862 | if (EX_ISSYNC(fhp->fh_export)) | ||
| 1863 | host_err = nfsd_sync_dir(dentry); | ||
| 1864 | 1854 | ||
| 1865 | out_drop: | ||
| 1866 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1855 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 
| 1867 | out_nfserr: | 1856 | out_nfserr: | 
| 1868 | err = nfserrno(host_err); | 1857 | err = nfserrno(host_err); | 
