diff options
-rw-r--r-- | Documentation/filesystems/Locking | 3 | ||||
-rw-r--r-- | Documentation/filesystems/vfs.txt | 4 | ||||
-rw-r--r-- | fs/fuse/file.c | 4 | ||||
-rw-r--r-- | fs/inode.c | 56 | ||||
-rw-r--r-- | fs/ncpfs/file.c | 6 | ||||
-rw-r--r-- | fs/ntfs/file.c | 4 | ||||
-rw-r--r-- | fs/pipe.c | 7 | ||||
-rw-r--r-- | fs/splice.c | 6 | ||||
-rw-r--r-- | fs/xfs/xfs_file.c | 7 | ||||
-rw-r--r-- | include/linux/fs.h | 10 | ||||
-rw-r--r-- | mm/filemap.c | 4 | ||||
-rw-r--r-- | mm/filemap_xip.c | 4 |
12 files changed, 86 insertions, 29 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 4fca82e5276..d5a269a51a9 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
@@ -62,6 +62,7 @@ ata *); | |||
62 | int (*removexattr) (struct dentry *, const char *); | 62 | int (*removexattr) (struct dentry *, const char *); |
63 | void (*truncate_range)(struct inode *, loff_t, loff_t); | 63 | void (*truncate_range)(struct inode *, loff_t, loff_t); |
64 | int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); | 64 | int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); |
65 | void (*update_time)(struct inode *, struct timespec *, int); | ||
65 | 66 | ||
66 | locking rules: | 67 | locking rules: |
67 | all may block | 68 | all may block |
@@ -89,6 +90,8 @@ listxattr: no | |||
89 | removexattr: yes | 90 | removexattr: yes |
90 | truncate_range: yes | 91 | truncate_range: yes |
91 | fiemap: no | 92 | fiemap: no |
93 | update_time: no | ||
94 | |||
92 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on | 95 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on |
93 | victim. | 96 | victim. |
94 | cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. | 97 | cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. |
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 0d049202808..b2aa722e5ea 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
@@ -364,6 +364,7 @@ struct inode_operations { | |||
364 | ssize_t (*listxattr) (struct dentry *, char *, size_t); | 364 | ssize_t (*listxattr) (struct dentry *, char *, size_t); |
365 | int (*removexattr) (struct dentry *, const char *); | 365 | int (*removexattr) (struct dentry *, const char *); |
366 | void (*truncate_range)(struct inode *, loff_t, loff_t); | 366 | void (*truncate_range)(struct inode *, loff_t, loff_t); |
367 | void (*update_time)(struct inode *, struct timespec *, int); | ||
367 | }; | 368 | }; |
368 | 369 | ||
369 | Again, all methods are called without any locks being held, unless | 370 | Again, all methods are called without any locks being held, unless |
@@ -475,6 +476,9 @@ otherwise noted. | |||
475 | truncate_range: a method provided by the underlying filesystem to truncate a | 476 | truncate_range: a method provided by the underlying filesystem to truncate a |
476 | range of blocks , i.e. punch a hole somewhere in a file. | 477 | range of blocks , i.e. punch a hole somewhere in a file. |
477 | 478 | ||
479 | update_time: called by the VFS to update a specific time or the i_version of | ||
480 | an inode. If this is not defined the VFS will update the inode itself | ||
481 | and call mark_inode_dirty_sync. | ||
478 | 482 | ||
479 | The Address Space Object | 483 | The Address Space Object |
480 | ======================== | 484 | ======================== |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 504e61b7fd7..9562109d3a8 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -962,7 +962,9 @@ static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
962 | if (err) | 962 | if (err) |
963 | goto out; | 963 | goto out; |
964 | 964 | ||
965 | file_update_time(file); | 965 | err = file_update_time(file); |
966 | if (err) | ||
967 | goto out; | ||
966 | 968 | ||
967 | if (file->f_flags & O_DIRECT) { | 969 | if (file->f_flags & O_DIRECT) { |
968 | written = generic_file_direct_write(iocb, iov, &nr_segs, | 970 | written = generic_file_direct_write(iocb, iov, &nr_segs, |
diff --git a/fs/inode.c b/fs/inode.c index a79555e492e..f0335fc315e 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -1487,6 +1487,27 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, | |||
1487 | return 0; | 1487 | return 0; |
1488 | } | 1488 | } |
1489 | 1489 | ||
1490 | /* | ||
1491 | * This does the actual work of updating an inodes time or version. Must have | ||
1492 | * had called mnt_want_write() before calling this. | ||
1493 | */ | ||
1494 | static int update_time(struct inode *inode, struct timespec *time, int flags) | ||
1495 | { | ||
1496 | if (inode->i_op->update_time) | ||
1497 | return inode->i_op->update_time(inode, time, flags); | ||
1498 | |||
1499 | if (flags & S_ATIME) | ||
1500 | inode->i_atime = *time; | ||
1501 | if (flags & S_VERSION) | ||
1502 | inode_inc_iversion(inode); | ||
1503 | if (flags & S_CTIME) | ||
1504 | inode->i_ctime = *time; | ||
1505 | if (flags & S_MTIME) | ||
1506 | inode->i_mtime = *time; | ||
1507 | mark_inode_dirty_sync(inode); | ||
1508 | return 0; | ||
1509 | } | ||
1510 | |||
1490 | /** | 1511 | /** |
1491 | * touch_atime - update the access time | 1512 | * touch_atime - update the access time |
1492 | * @path: the &struct path to update | 1513 | * @path: the &struct path to update |
@@ -1524,8 +1545,14 @@ void touch_atime(struct path *path) | |||
1524 | if (mnt_want_write(mnt)) | 1545 | if (mnt_want_write(mnt)) |
1525 | return; | 1546 | return; |
1526 | 1547 | ||
1527 | inode->i_atime = now; | 1548 | /* |
1528 | mark_inode_dirty_sync(inode); | 1549 | * File systems can error out when updating inodes if they need to |
1550 | * allocate new space to modify an inode (such is the case for | ||
1551 | * Btrfs), but since we touch atime while walking down the path we | ||
1552 | * really don't care if we failed to update the atime of the file, | ||
1553 | * so just ignore the return value. | ||
1554 | */ | ||
1555 | update_time(inode, &now, S_ATIME); | ||
1529 | mnt_drop_write(mnt); | 1556 | mnt_drop_write(mnt); |
1530 | } | 1557 | } |
1531 | EXPORT_SYMBOL(touch_atime); | 1558 | EXPORT_SYMBOL(touch_atime); |
@@ -1604,18 +1631,20 @@ EXPORT_SYMBOL(file_remove_suid); | |||
1604 | * usage in the file write path of filesystems, and filesystems may | 1631 | * usage in the file write path of filesystems, and filesystems may |
1605 | * choose to explicitly ignore update via this function with the | 1632 | * choose to explicitly ignore update via this function with the |
1606 | * S_NOCMTIME inode flag, e.g. for network filesystem where these | 1633 | * S_NOCMTIME inode flag, e.g. for network filesystem where these |
1607 | * timestamps are handled by the server. | 1634 | * timestamps are handled by the server. This can return an error for |
1635 | * file systems who need to allocate space in order to update an inode. | ||
1608 | */ | 1636 | */ |
1609 | 1637 | ||
1610 | void file_update_time(struct file *file) | 1638 | int file_update_time(struct file *file) |
1611 | { | 1639 | { |
1612 | struct inode *inode = file->f_path.dentry->d_inode; | 1640 | struct inode *inode = file->f_path.dentry->d_inode; |
1613 | struct timespec now; | 1641 | struct timespec now; |
1614 | enum { S_MTIME = 1, S_CTIME = 2, S_VERSION = 4 } sync_it = 0; | 1642 | int sync_it = 0; |
1643 | int ret; | ||
1615 | 1644 | ||
1616 | /* First try to exhaust all avenues to not sync */ | 1645 | /* First try to exhaust all avenues to not sync */ |
1617 | if (IS_NOCMTIME(inode)) | 1646 | if (IS_NOCMTIME(inode)) |
1618 | return; | 1647 | return 0; |
1619 | 1648 | ||
1620 | now = current_fs_time(inode->i_sb); | 1649 | now = current_fs_time(inode->i_sb); |
1621 | if (!timespec_equal(&inode->i_mtime, &now)) | 1650 | if (!timespec_equal(&inode->i_mtime, &now)) |
@@ -1628,21 +1657,16 @@ void file_update_time(struct file *file) | |||
1628 | sync_it |= S_VERSION; | 1657 | sync_it |= S_VERSION; |
1629 | 1658 | ||
1630 | if (!sync_it) | 1659 | if (!sync_it) |
1631 | return; | 1660 | return 0; |
1632 | 1661 | ||
1633 | /* Finally allowed to write? Takes lock. */ | 1662 | /* Finally allowed to write? Takes lock. */ |
1634 | if (mnt_want_write_file(file)) | 1663 | if (mnt_want_write_file(file)) |
1635 | return; | 1664 | return 0; |
1636 | 1665 | ||
1637 | /* Only change inode inside the lock region */ | 1666 | ret = update_time(inode, &now, sync_it); |
1638 | if (sync_it & S_VERSION) | ||
1639 | inode_inc_iversion(inode); | ||
1640 | if (sync_it & S_CTIME) | ||
1641 | inode->i_ctime = now; | ||
1642 | if (sync_it & S_MTIME) | ||
1643 | inode->i_mtime = now; | ||
1644 | mark_inode_dirty_sync(inode); | ||
1645 | mnt_drop_write_file(file); | 1667 | mnt_drop_write_file(file); |
1668 | |||
1669 | return ret; | ||
1646 | } | 1670 | } |
1647 | EXPORT_SYMBOL(file_update_time); | 1671 | EXPORT_SYMBOL(file_update_time); |
1648 | 1672 | ||
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index 3ff5fcc1528..122e260247f 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c | |||
@@ -221,6 +221,10 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t * | |||
221 | 221 | ||
222 | already_written = 0; | 222 | already_written = 0; |
223 | 223 | ||
224 | errno = file_update_time(file); | ||
225 | if (errno) | ||
226 | goto outrel; | ||
227 | |||
224 | bouncebuffer = vmalloc(bufsize); | 228 | bouncebuffer = vmalloc(bufsize); |
225 | if (!bouncebuffer) { | 229 | if (!bouncebuffer) { |
226 | errno = -EIO; /* -ENOMEM */ | 230 | errno = -EIO; /* -ENOMEM */ |
@@ -252,8 +256,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t * | |||
252 | } | 256 | } |
253 | vfree(bouncebuffer); | 257 | vfree(bouncebuffer); |
254 | 258 | ||
255 | file_update_time(file); | ||
256 | |||
257 | *ppos = pos; | 259 | *ppos = pos; |
258 | 260 | ||
259 | if (pos > i_size_read(inode)) { | 261 | if (pos > i_size_read(inode)) { |
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 8639169221c..7389d2d5e51 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -2096,7 +2096,9 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb, | |||
2096 | err = file_remove_suid(file); | 2096 | err = file_remove_suid(file); |
2097 | if (err) | 2097 | if (err) |
2098 | goto out; | 2098 | goto out; |
2099 | file_update_time(file); | 2099 | err = file_update_time(file); |
2100 | if (err) | ||
2101 | goto out; | ||
2100 | written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos, | 2102 | written = ntfs_file_buffered_write(iocb, iov, nr_segs, pos, ppos, |
2101 | count); | 2103 | count); |
2102 | out: | 2104 | out: |
@@ -654,8 +654,11 @@ out: | |||
654 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); | 654 | wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); |
655 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); | 655 | kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); |
656 | } | 656 | } |
657 | if (ret > 0) | 657 | if (ret > 0) { |
658 | file_update_time(filp); | 658 | int err = file_update_time(filp); |
659 | if (err) | ||
660 | ret = err; | ||
661 | } | ||
659 | return ret; | 662 | return ret; |
660 | } | 663 | } |
661 | 664 | ||
diff --git a/fs/splice.c b/fs/splice.c index f8476841eb0..47c4c1ad0c0 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -1003,8 +1003,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
1003 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); | 1003 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
1004 | ret = file_remove_suid(out); | 1004 | ret = file_remove_suid(out); |
1005 | if (!ret) { | 1005 | if (!ret) { |
1006 | file_update_time(out); | 1006 | ret = file_update_time(out); |
1007 | ret = splice_from_pipe_feed(pipe, &sd, pipe_to_file); | 1007 | if (!ret) |
1008 | ret = splice_from_pipe_feed(pipe, &sd, | ||
1009 | pipe_to_file); | ||
1008 | } | 1010 | } |
1009 | mutex_unlock(&inode->i_mutex); | 1011 | mutex_unlock(&inode->i_mutex); |
1010 | } while (ret > 0); | 1012 | } while (ret > 0); |
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 8d214b87f6b..9f7ec15a652 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -586,8 +586,11 @@ restart: | |||
586 | * lock above. Eventually we should look into a way to avoid | 586 | * lock above. Eventually we should look into a way to avoid |
587 | * the pointless lock roundtrip. | 587 | * the pointless lock roundtrip. |
588 | */ | 588 | */ |
589 | if (likely(!(file->f_mode & FMODE_NOCMTIME))) | 589 | if (likely(!(file->f_mode & FMODE_NOCMTIME))) { |
590 | file_update_time(file); | 590 | error = file_update_time(file); |
591 | if (error) | ||
592 | return error; | ||
593 | } | ||
591 | 594 | ||
592 | /* | 595 | /* |
593 | * If we're writing the file then make sure to clear the setuid and | 596 | * If we're writing the file then make sure to clear the setuid and |
diff --git a/include/linux/fs.h b/include/linux/fs.h index cdc1a963094..57fc70574d2 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1684,6 +1684,7 @@ struct inode_operations { | |||
1684 | void (*truncate_range)(struct inode *, loff_t, loff_t); | 1684 | void (*truncate_range)(struct inode *, loff_t, loff_t); |
1685 | int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, | 1685 | int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, |
1686 | u64 len); | 1686 | u64 len); |
1687 | int (*update_time)(struct inode *, struct timespec *, int); | ||
1687 | } ____cacheline_aligned; | 1688 | } ____cacheline_aligned; |
1688 | 1689 | ||
1689 | struct seq_file; | 1690 | struct seq_file; |
@@ -1843,6 +1844,13 @@ static inline void inode_inc_iversion(struct inode *inode) | |||
1843 | spin_unlock(&inode->i_lock); | 1844 | spin_unlock(&inode->i_lock); |
1844 | } | 1845 | } |
1845 | 1846 | ||
1847 | enum file_time_flags { | ||
1848 | S_ATIME = 1, | ||
1849 | S_MTIME = 2, | ||
1850 | S_CTIME = 4, | ||
1851 | S_VERSION = 8, | ||
1852 | }; | ||
1853 | |||
1846 | extern void touch_atime(struct path *); | 1854 | extern void touch_atime(struct path *); |
1847 | static inline void file_accessed(struct file *file) | 1855 | static inline void file_accessed(struct file *file) |
1848 | { | 1856 | { |
@@ -2579,7 +2587,7 @@ extern int inode_change_ok(const struct inode *, struct iattr *); | |||
2579 | extern int inode_newsize_ok(const struct inode *, loff_t offset); | 2587 | extern int inode_newsize_ok(const struct inode *, loff_t offset); |
2580 | extern void setattr_copy(struct inode *inode, const struct iattr *attr); | 2588 | extern void setattr_copy(struct inode *inode, const struct iattr *attr); |
2581 | 2589 | ||
2582 | extern void file_update_time(struct file *file); | 2590 | extern int file_update_time(struct file *file); |
2583 | 2591 | ||
2584 | extern int generic_show_options(struct seq_file *m, struct dentry *root); | 2592 | extern int generic_show_options(struct seq_file *m, struct dentry *root); |
2585 | extern void save_mount_options(struct super_block *sb, char *options); | 2593 | extern void save_mount_options(struct super_block *sb, char *options); |
diff --git a/mm/filemap.c b/mm/filemap.c index 21e5abfbcdf..51070f1f1b5 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -2463,7 +2463,9 @@ ssize_t __generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
2463 | if (err) | 2463 | if (err) |
2464 | goto out; | 2464 | goto out; |
2465 | 2465 | ||
2466 | file_update_time(file); | 2466 | err = file_update_time(file); |
2467 | if (err) | ||
2468 | goto out; | ||
2467 | 2469 | ||
2468 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ | 2470 | /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ |
2469 | if (unlikely(file->f_flags & O_DIRECT)) { | 2471 | if (unlikely(file->f_flags & O_DIRECT)) { |
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index a4eb3113222..213ca1f5340 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c | |||
@@ -426,7 +426,9 @@ xip_file_write(struct file *filp, const char __user *buf, size_t len, | |||
426 | if (ret) | 426 | if (ret) |
427 | goto out_backing; | 427 | goto out_backing; |
428 | 428 | ||
429 | file_update_time(filp); | 429 | ret = file_update_time(filp); |
430 | if (ret) | ||
431 | goto out_backing; | ||
430 | 432 | ||
431 | ret = __xip_file_write (filp, buf, count, pos, ppos); | 433 | ret = __xip_file_write (filp, buf, count, pos, ppos); |
432 | 434 | ||