diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/block_dev.c | 10 | ||||
| -rw-r--r-- | fs/buffer.c | 13 | ||||
| -rw-r--r-- | fs/dcache.c | 68 | ||||
| -rw-r--r-- | fs/locks.c | 6 | ||||
| -rw-r--r-- | fs/namei.c | 26 | ||||
| -rw-r--r-- | fs/pipe.c | 10 | ||||
| -rw-r--r-- | fs/udf/super.c | 57 | ||||
| -rw-r--r-- | fs/utimes.c | 59 |
8 files changed, 119 insertions, 130 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 470c10ceb0fb..10d8a0aa871a 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -931,8 +931,16 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part) | |||
| 931 | struct gendisk *disk; | 931 | struct gendisk *disk; |
| 932 | int ret; | 932 | int ret; |
| 933 | int part; | 933 | int part; |
| 934 | int perm = 0; | ||
| 934 | 935 | ||
| 935 | ret = devcgroup_inode_permission(bdev->bd_inode, file->f_mode); | 936 | if (file->f_mode & FMODE_READ) |
| 937 | perm |= MAY_READ; | ||
| 938 | if (file->f_mode & FMODE_WRITE) | ||
| 939 | perm |= MAY_WRITE; | ||
| 940 | /* | ||
| 941 | * hooks: /n/, see "layering violations". | ||
| 942 | */ | ||
| 943 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); | ||
| 936 | if (ret != 0) | 944 | if (ret != 0) |
| 937 | return ret; | 945 | return ret; |
| 938 | 946 | ||
diff --git a/fs/buffer.c b/fs/buffer.c index a073f3f4f013..0f51c0f7c266 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -821,7 +821,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) | |||
| 821 | * contents - it is a noop if I/O is still in | 821 | * contents - it is a noop if I/O is still in |
| 822 | * flight on potentially older contents. | 822 | * flight on potentially older contents. |
| 823 | */ | 823 | */ |
| 824 | ll_rw_block(SWRITE, 1, &bh); | 824 | ll_rw_block(SWRITE_SYNC, 1, &bh); |
| 825 | brelse(bh); | 825 | brelse(bh); |
| 826 | spin_lock(lock); | 826 | spin_lock(lock); |
| 827 | } | 827 | } |
| @@ -2940,16 +2940,19 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) | |||
| 2940 | for (i = 0; i < nr; i++) { | 2940 | for (i = 0; i < nr; i++) { |
| 2941 | struct buffer_head *bh = bhs[i]; | 2941 | struct buffer_head *bh = bhs[i]; |
| 2942 | 2942 | ||
| 2943 | if (rw == SWRITE) | 2943 | if (rw == SWRITE || rw == SWRITE_SYNC) |
| 2944 | lock_buffer(bh); | 2944 | lock_buffer(bh); |
| 2945 | else if (test_set_buffer_locked(bh)) | 2945 | else if (test_set_buffer_locked(bh)) |
| 2946 | continue; | 2946 | continue; |
| 2947 | 2947 | ||
| 2948 | if (rw == WRITE || rw == SWRITE) { | 2948 | if (rw == WRITE || rw == SWRITE || rw == SWRITE_SYNC) { |
| 2949 | if (test_clear_buffer_dirty(bh)) { | 2949 | if (test_clear_buffer_dirty(bh)) { |
| 2950 | bh->b_end_io = end_buffer_write_sync; | 2950 | bh->b_end_io = end_buffer_write_sync; |
| 2951 | get_bh(bh); | 2951 | get_bh(bh); |
| 2952 | submit_bh(WRITE, bh); | 2952 | if (rw == SWRITE_SYNC) |
| 2953 | submit_bh(WRITE_SYNC, bh); | ||
| 2954 | else | ||
| 2955 | submit_bh(WRITE, bh); | ||
| 2953 | continue; | 2956 | continue; |
| 2954 | } | 2957 | } |
| 2955 | } else { | 2958 | } else { |
| @@ -2978,7 +2981,7 @@ int sync_dirty_buffer(struct buffer_head *bh) | |||
| 2978 | if (test_clear_buffer_dirty(bh)) { | 2981 | if (test_clear_buffer_dirty(bh)) { |
| 2979 | get_bh(bh); | 2982 | get_bh(bh); |
| 2980 | bh->b_end_io = end_buffer_write_sync; | 2983 | bh->b_end_io = end_buffer_write_sync; |
| 2981 | ret = submit_bh(WRITE, bh); | 2984 | ret = submit_bh(WRITE_SYNC, bh); |
| 2982 | wait_on_buffer(bh); | 2985 | wait_on_buffer(bh); |
| 2983 | if (buffer_eopnotsupp(bh)) { | 2986 | if (buffer_eopnotsupp(bh)) { |
| 2984 | clear_buffer_eopnotsupp(bh); | 2987 | clear_buffer_eopnotsupp(bh); |
diff --git a/fs/dcache.c b/fs/dcache.c index 3ee588d5f585..6068c25b393c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
| 18 | #include <linux/string.h> | 18 | #include <linux/string.h> |
| 19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
| 20 | #include <linux/fdtable.h> | ||
| 20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
| 21 | #include <linux/fsnotify.h> | 22 | #include <linux/fsnotify.h> |
| 22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| @@ -106,9 +107,10 @@ static void dentry_lru_remove(struct dentry *dentry) | |||
| 106 | /* | 107 | /* |
| 107 | * Release the dentry's inode, using the filesystem | 108 | * Release the dentry's inode, using the filesystem |
| 108 | * d_iput() operation if defined. | 109 | * d_iput() operation if defined. |
| 109 | * Called with dcache_lock and per dentry lock held, drops both. | ||
| 110 | */ | 110 | */ |
| 111 | static void dentry_iput(struct dentry * dentry) | 111 | static void dentry_iput(struct dentry * dentry) |
| 112 | __releases(dentry->d_lock) | ||
| 113 | __releases(dcache_lock) | ||
| 112 | { | 114 | { |
| 113 | struct inode *inode = dentry->d_inode; | 115 | struct inode *inode = dentry->d_inode; |
| 114 | if (inode) { | 116 | if (inode) { |
| @@ -132,12 +134,13 @@ static void dentry_iput(struct dentry * dentry) | |||
| 132 | * d_kill - kill dentry and return parent | 134 | * d_kill - kill dentry and return parent |
| 133 | * @dentry: dentry to kill | 135 | * @dentry: dentry to kill |
| 134 | * | 136 | * |
| 135 | * Called with dcache_lock and d_lock, releases both. The dentry must | 137 | * The dentry must already be unhashed and removed from the LRU. |
| 136 | * already be unhashed and removed from the LRU. | ||
| 137 | * | 138 | * |
| 138 | * If this is the root of the dentry tree, return NULL. | 139 | * If this is the root of the dentry tree, return NULL. |
| 139 | */ | 140 | */ |
| 140 | static struct dentry *d_kill(struct dentry *dentry) | 141 | static struct dentry *d_kill(struct dentry *dentry) |
| 142 | __releases(dentry->d_lock) | ||
| 143 | __releases(dcache_lock) | ||
| 141 | { | 144 | { |
| 142 | struct dentry *parent; | 145 | struct dentry *parent; |
| 143 | 146 | ||
| @@ -383,11 +386,11 @@ restart: | |||
| 383 | * Try to prune ancestors as well. This is necessary to prevent | 386 | * Try to prune ancestors as well. This is necessary to prevent |
| 384 | * quadratic behavior of shrink_dcache_parent(), but is also expected | 387 | * quadratic behavior of shrink_dcache_parent(), but is also expected |
| 385 | * to be beneficial in reducing dentry cache fragmentation. | 388 | * to be beneficial in reducing dentry cache fragmentation. |
| 386 | * | ||
| 387 | * Called with dcache_lock, drops it and then regains. | ||
| 388 | * Called with dentry->d_lock held, drops it. | ||
| 389 | */ | 389 | */ |
| 390 | static void prune_one_dentry(struct dentry * dentry) | 390 | static void prune_one_dentry(struct dentry * dentry) |
| 391 | __releases(dentry->d_lock) | ||
| 392 | __releases(dcache_lock) | ||
| 393 | __acquires(dcache_lock) | ||
| 391 | { | 394 | { |
| 392 | __d_drop(dentry); | 395 | __d_drop(dentry); |
| 393 | dentry = d_kill(dentry); | 396 | dentry = d_kill(dentry); |
| @@ -1604,10 +1607,9 @@ static int d_isparent(struct dentry *p1, struct dentry *p2) | |||
| 1604 | * | 1607 | * |
| 1605 | * Note: If ever the locking in lock_rename() changes, then please | 1608 | * Note: If ever the locking in lock_rename() changes, then please |
| 1606 | * remember to update this too... | 1609 | * remember to update this too... |
| 1607 | * | ||
| 1608 | * On return, dcache_lock will have been unlocked. | ||
| 1609 | */ | 1610 | */ |
| 1610 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | 1611 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) |
| 1612 | __releases(dcache_lock) | ||
| 1611 | { | 1613 | { |
| 1612 | struct mutex *m1 = NULL, *m2 = NULL; | 1614 | struct mutex *m1 = NULL, *m2 = NULL; |
| 1613 | struct dentry *ret; | 1615 | struct dentry *ret; |
| @@ -1743,11 +1745,9 @@ out_nolock: | |||
| 1743 | shouldnt_be_hashed: | 1745 | shouldnt_be_hashed: |
| 1744 | spin_unlock(&dcache_lock); | 1746 | spin_unlock(&dcache_lock); |
| 1745 | BUG(); | 1747 | BUG(); |
| 1746 | goto shouldnt_be_hashed; | ||
| 1747 | } | 1748 | } |
| 1748 | 1749 | ||
| 1749 | static int prepend(char **buffer, int *buflen, const char *str, | 1750 | static int prepend(char **buffer, int *buflen, const char *str, int namelen) |
| 1750 | int namelen) | ||
| 1751 | { | 1751 | { |
| 1752 | *buflen -= namelen; | 1752 | *buflen -= namelen; |
| 1753 | if (*buflen < 0) | 1753 | if (*buflen < 0) |
| @@ -1757,8 +1757,13 @@ static int prepend(char **buffer, int *buflen, const char *str, | |||
| 1757 | return 0; | 1757 | return 0; |
| 1758 | } | 1758 | } |
| 1759 | 1759 | ||
| 1760 | static int prepend_name(char **buffer, int *buflen, struct qstr *name) | ||
| 1761 | { | ||
| 1762 | return prepend(buffer, buflen, name->name, name->len); | ||
| 1763 | } | ||
| 1764 | |||
| 1760 | /** | 1765 | /** |
| 1761 | * d_path - return the path of a dentry | 1766 | * __d_path - return the path of a dentry |
| 1762 | * @path: the dentry/vfsmount to report | 1767 | * @path: the dentry/vfsmount to report |
| 1763 | * @root: root vfsmnt/dentry (may be modified by this function) | 1768 | * @root: root vfsmnt/dentry (may be modified by this function) |
| 1764 | * @buffer: buffer to return value in | 1769 | * @buffer: buffer to return value in |
| @@ -1779,9 +1784,10 @@ char *__d_path(const struct path *path, struct path *root, | |||
| 1779 | { | 1784 | { |
| 1780 | struct dentry *dentry = path->dentry; | 1785 | struct dentry *dentry = path->dentry; |
| 1781 | struct vfsmount *vfsmnt = path->mnt; | 1786 | struct vfsmount *vfsmnt = path->mnt; |
| 1782 | char * end = buffer+buflen; | 1787 | char *end = buffer + buflen; |
| 1783 | char * retval; | 1788 | char *retval; |
| 1784 | 1789 | ||
| 1790 | spin_lock(&vfsmount_lock); | ||
| 1785 | prepend(&end, &buflen, "\0", 1); | 1791 | prepend(&end, &buflen, "\0", 1); |
| 1786 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | 1792 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && |
| 1787 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) | 1793 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
| @@ -1800,38 +1806,37 @@ char *__d_path(const struct path *path, struct path *root, | |||
| 1800 | break; | 1806 | break; |
| 1801 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1807 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
| 1802 | /* Global root? */ | 1808 | /* Global root? */ |
| 1803 | spin_lock(&vfsmount_lock); | ||
| 1804 | if (vfsmnt->mnt_parent == vfsmnt) { | 1809 | if (vfsmnt->mnt_parent == vfsmnt) { |
| 1805 | spin_unlock(&vfsmount_lock); | ||
| 1806 | goto global_root; | 1810 | goto global_root; |
| 1807 | } | 1811 | } |
| 1808 | dentry = vfsmnt->mnt_mountpoint; | 1812 | dentry = vfsmnt->mnt_mountpoint; |
| 1809 | vfsmnt = vfsmnt->mnt_parent; | 1813 | vfsmnt = vfsmnt->mnt_parent; |
| 1810 | spin_unlock(&vfsmount_lock); | ||
| 1811 | continue; | 1814 | continue; |
| 1812 | } | 1815 | } |
| 1813 | parent = dentry->d_parent; | 1816 | parent = dentry->d_parent; |
| 1814 | prefetch(parent); | 1817 | prefetch(parent); |
| 1815 | if ((prepend(&end, &buflen, dentry->d_name.name, | 1818 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || |
| 1816 | dentry->d_name.len) != 0) || | ||
| 1817 | (prepend(&end, &buflen, "/", 1) != 0)) | 1819 | (prepend(&end, &buflen, "/", 1) != 0)) |
| 1818 | goto Elong; | 1820 | goto Elong; |
| 1819 | retval = end; | 1821 | retval = end; |
| 1820 | dentry = parent; | 1822 | dentry = parent; |
| 1821 | } | 1823 | } |
| 1822 | 1824 | ||
| 1825 | out: | ||
| 1826 | spin_unlock(&vfsmount_lock); | ||
| 1823 | return retval; | 1827 | return retval; |
| 1824 | 1828 | ||
| 1825 | global_root: | 1829 | global_root: |
| 1826 | retval += 1; /* hit the slash */ | 1830 | retval += 1; /* hit the slash */ |
| 1827 | if (prepend(&retval, &buflen, dentry->d_name.name, | 1831 | if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) |
| 1828 | dentry->d_name.len) != 0) | ||
| 1829 | goto Elong; | 1832 | goto Elong; |
| 1830 | root->mnt = vfsmnt; | 1833 | root->mnt = vfsmnt; |
| 1831 | root->dentry = dentry; | 1834 | root->dentry = dentry; |
| 1832 | return retval; | 1835 | goto out; |
| 1836 | |||
| 1833 | Elong: | 1837 | Elong: |
| 1834 | return ERR_PTR(-ENAMETOOLONG); | 1838 | retval = ERR_PTR(-ENAMETOOLONG); |
| 1839 | goto out; | ||
| 1835 | } | 1840 | } |
| 1836 | 1841 | ||
| 1837 | /** | 1842 | /** |
| @@ -1845,9 +1850,9 @@ Elong: | |||
| 1845 | * | 1850 | * |
| 1846 | * Returns the buffer or an error code if the path was too long. | 1851 | * Returns the buffer or an error code if the path was too long. |
| 1847 | * | 1852 | * |
| 1848 | * "buflen" should be positive. Caller holds the dcache_lock. | 1853 | * "buflen" should be positive. |
| 1849 | */ | 1854 | */ |
| 1850 | char *d_path(struct path *path, char *buf, int buflen) | 1855 | char *d_path(const struct path *path, char *buf, int buflen) |
| 1851 | { | 1856 | { |
| 1852 | char *res; | 1857 | char *res; |
| 1853 | struct path root; | 1858 | struct path root; |
| @@ -1915,16 +1920,11 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
| 1915 | retval = end-1; | 1920 | retval = end-1; |
| 1916 | *retval = '/'; | 1921 | *retval = '/'; |
| 1917 | 1922 | ||
| 1918 | for (;;) { | 1923 | while (!IS_ROOT(dentry)) { |
| 1919 | struct dentry *parent; | 1924 | struct dentry *parent = dentry->d_parent; |
| 1920 | if (IS_ROOT(dentry)) | ||
| 1921 | break; | ||
| 1922 | 1925 | ||
| 1923 | parent = dentry->d_parent; | ||
| 1924 | prefetch(parent); | 1926 | prefetch(parent); |
| 1925 | 1927 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || | |
| 1926 | if ((prepend(&end, &buflen, dentry->d_name.name, | ||
| 1927 | dentry->d_name.len) != 0) || | ||
| 1928 | (prepend(&end, &buflen, "/", 1) != 0)) | 1928 | (prepend(&end, &buflen, "/", 1) != 0)) |
| 1929 | goto Elong; | 1929 | goto Elong; |
| 1930 | 1930 | ||
| @@ -1975,7 +1975,7 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) | |||
| 1975 | error = -ENOENT; | 1975 | error = -ENOENT; |
| 1976 | /* Has the current directory has been unlinked? */ | 1976 | /* Has the current directory has been unlinked? */ |
| 1977 | spin_lock(&dcache_lock); | 1977 | spin_lock(&dcache_lock); |
| 1978 | if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { | 1978 | if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) { |
| 1979 | unsigned long len; | 1979 | unsigned long len; |
| 1980 | struct path tmp = root; | 1980 | struct path tmp = root; |
| 1981 | char * cwd; | 1981 | char * cwd; |
diff --git a/fs/locks.c b/fs/locks.c index 11dbf08651b7..dce8c747371c 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
| @@ -561,9 +561,6 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl) | |||
| 561 | /* insert into file's list */ | 561 | /* insert into file's list */ |
| 562 | fl->fl_next = *pos; | 562 | fl->fl_next = *pos; |
| 563 | *pos = fl; | 563 | *pos = fl; |
| 564 | |||
| 565 | if (fl->fl_ops && fl->fl_ops->fl_insert) | ||
| 566 | fl->fl_ops->fl_insert(fl); | ||
| 567 | } | 564 | } |
| 568 | 565 | ||
| 569 | /* | 566 | /* |
| @@ -586,9 +583,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p) | |||
| 586 | fl->fl_fasync = NULL; | 583 | fl->fl_fasync = NULL; |
| 587 | } | 584 | } |
| 588 | 585 | ||
| 589 | if (fl->fl_ops && fl->fl_ops->fl_remove) | ||
| 590 | fl->fl_ops->fl_remove(fl); | ||
| 591 | |||
| 592 | if (fl->fl_nspid) { | 586 | if (fl->fl_nspid) { |
| 593 | put_pid(fl->fl_nspid); | 587 | put_pid(fl->fl_nspid); |
| 594 | fl->fl_nspid = NULL; | 588 | fl->fl_nspid = NULL; |
diff --git a/fs/namei.c b/fs/namei.c index c7e43536c49a..01e67dddcc3d 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -581,15 +581,13 @@ static __always_inline int link_path_walk(const char *name, struct nameidata *nd | |||
| 581 | int result; | 581 | int result; |
| 582 | 582 | ||
| 583 | /* make sure the stuff we saved doesn't go away */ | 583 | /* make sure the stuff we saved doesn't go away */ |
| 584 | dget(save.dentry); | 584 | path_get(&save); |
| 585 | mntget(save.mnt); | ||
| 586 | 585 | ||
| 587 | result = __link_path_walk(name, nd); | 586 | result = __link_path_walk(name, nd); |
| 588 | if (result == -ESTALE) { | 587 | if (result == -ESTALE) { |
| 589 | /* nd->path had been dropped */ | 588 | /* nd->path had been dropped */ |
| 590 | nd->path = save; | 589 | nd->path = save; |
| 591 | dget(nd->path.dentry); | 590 | path_get(&nd->path); |
| 592 | mntget(nd->path.mnt); | ||
| 593 | nd->flags |= LOOKUP_REVAL; | 591 | nd->flags |= LOOKUP_REVAL; |
| 594 | result = __link_path_walk(name, nd); | 592 | result = __link_path_walk(name, nd); |
| 595 | } | 593 | } |
| @@ -1216,8 +1214,9 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
| 1216 | nd->flags = flags; | 1214 | nd->flags = flags; |
| 1217 | nd->depth = 0; | 1215 | nd->depth = 0; |
| 1218 | 1216 | ||
| 1219 | nd->path.mnt = mntget(mnt); | 1217 | nd->path.dentry = dentry; |
| 1220 | nd->path.dentry = dget(dentry); | 1218 | nd->path.mnt = mnt; |
| 1219 | path_get(&nd->path); | ||
| 1221 | 1220 | ||
| 1222 | retval = path_walk(name, nd); | 1221 | retval = path_walk(name, nd); |
| 1223 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1222 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && |
| @@ -2857,16 +2856,17 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) | |||
| 2857 | { | 2856 | { |
| 2858 | struct nameidata nd; | 2857 | struct nameidata nd; |
| 2859 | void *cookie; | 2858 | void *cookie; |
| 2859 | int res; | ||
| 2860 | 2860 | ||
| 2861 | nd.depth = 0; | 2861 | nd.depth = 0; |
| 2862 | cookie = dentry->d_inode->i_op->follow_link(dentry, &nd); | 2862 | cookie = dentry->d_inode->i_op->follow_link(dentry, &nd); |
| 2863 | if (!IS_ERR(cookie)) { | 2863 | if (IS_ERR(cookie)) |
| 2864 | int res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); | 2864 | return PTR_ERR(cookie); |
| 2865 | if (dentry->d_inode->i_op->put_link) | 2865 | |
| 2866 | dentry->d_inode->i_op->put_link(dentry, &nd, cookie); | 2866 | res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd)); |
| 2867 | cookie = ERR_PTR(res); | 2867 | if (dentry->d_inode->i_op->put_link) |
| 2868 | } | 2868 | dentry->d_inode->i_op->put_link(dentry, &nd, cookie); |
| 2869 | return PTR_ERR(cookie); | 2869 | return res; |
| 2870 | } | 2870 | } |
| 2871 | 2871 | ||
| 2872 | int vfs_follow_link(struct nameidata *nd, const char *link) | 2872 | int vfs_follow_link(struct nameidata *nd, const char *link) |
| @@ -1003,8 +1003,7 @@ struct file *create_write_pipe(void) | |||
| 1003 | void free_write_pipe(struct file *f) | 1003 | void free_write_pipe(struct file *f) |
| 1004 | { | 1004 | { |
| 1005 | free_pipe_info(f->f_dentry->d_inode); | 1005 | free_pipe_info(f->f_dentry->d_inode); |
| 1006 | dput(f->f_path.dentry); | 1006 | path_put(&f->f_path); |
| 1007 | mntput(f->f_path.mnt); | ||
| 1008 | put_filp(f); | 1007 | put_filp(f); |
| 1009 | } | 1008 | } |
| 1010 | 1009 | ||
| @@ -1015,8 +1014,8 @@ struct file *create_read_pipe(struct file *wrf) | |||
| 1015 | return ERR_PTR(-ENFILE); | 1014 | return ERR_PTR(-ENFILE); |
| 1016 | 1015 | ||
| 1017 | /* Grab pipe from the writer */ | 1016 | /* Grab pipe from the writer */ |
| 1018 | f->f_path.mnt = mntget(wrf->f_path.mnt); | 1017 | f->f_path = wrf->f_path; |
| 1019 | f->f_path.dentry = dget(wrf->f_path.dentry); | 1018 | path_get(&wrf->f_path); |
| 1020 | f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping; | 1019 | f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping; |
| 1021 | 1020 | ||
| 1022 | f->f_pos = 0; | 1021 | f->f_pos = 0; |
| @@ -1068,8 +1067,7 @@ int do_pipe(int *fd) | |||
| 1068 | err_fdr: | 1067 | err_fdr: |
| 1069 | put_unused_fd(fdr); | 1068 | put_unused_fd(fdr); |
| 1070 | err_read_pipe: | 1069 | err_read_pipe: |
| 1071 | dput(fr->f_dentry); | 1070 | path_put(&fr->f_path); |
| 1072 | mntput(fr->f_vfsmnt); | ||
| 1073 | put_filp(fr); | 1071 | put_filp(fr); |
| 1074 | err_write_pipe: | 1072 | err_write_pipe: |
| 1075 | free_write_pipe(fw); | 1073 | free_write_pipe(fw); |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 7a5f69be6ac2..44cc702f96cc 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
| @@ -682,38 +682,26 @@ static int udf_vrs(struct super_block *sb, int silent) | |||
| 682 | /* | 682 | /* |
| 683 | * Check whether there is an anchor block in the given block | 683 | * Check whether there is an anchor block in the given block |
| 684 | */ | 684 | */ |
| 685 | static int udf_check_anchor_block(struct super_block *sb, sector_t block, | 685 | static int udf_check_anchor_block(struct super_block *sb, sector_t block) |
| 686 | bool varconv) | ||
| 687 | { | 686 | { |
| 688 | struct buffer_head *bh = NULL; | 687 | struct buffer_head *bh; |
| 689 | tag *t; | ||
| 690 | uint16_t ident; | 688 | uint16_t ident; |
| 691 | uint32_t location; | ||
| 692 | 689 | ||
| 693 | if (varconv) { | 690 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && |
| 694 | if (udf_fixed_to_variable(block) >= | 691 | udf_fixed_to_variable(block) >= |
| 695 | sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) | 692 | sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) |
| 696 | return 0; | 693 | return 0; |
| 697 | bh = sb_bread(sb, udf_fixed_to_variable(block)); | ||
| 698 | } | ||
| 699 | else | ||
| 700 | bh = sb_bread(sb, block); | ||
| 701 | 694 | ||
| 695 | bh = udf_read_tagged(sb, block, block, &ident); | ||
| 702 | if (!bh) | 696 | if (!bh) |
| 703 | return 0; | 697 | return 0; |
| 704 | |||
| 705 | t = (tag *)bh->b_data; | ||
| 706 | ident = le16_to_cpu(t->tagIdent); | ||
| 707 | location = le32_to_cpu(t->tagLocation); | ||
| 708 | brelse(bh); | 698 | brelse(bh); |
| 709 | if (ident != TAG_IDENT_AVDP) | 699 | |
| 710 | return 0; | 700 | return ident == TAG_IDENT_AVDP; |
| 711 | return location == block; | ||
| 712 | } | 701 | } |
| 713 | 702 | ||
| 714 | /* Search for an anchor volume descriptor pointer */ | 703 | /* Search for an anchor volume descriptor pointer */ |
| 715 | static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | 704 | static sector_t udf_scan_anchors(struct super_block *sb, sector_t lastblock) |
| 716 | sector_t lastblock) | ||
| 717 | { | 705 | { |
| 718 | sector_t last[6]; | 706 | sector_t last[6]; |
| 719 | int i; | 707 | int i; |
| @@ -739,7 +727,7 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | |||
| 739 | sb->s_blocksize_bits) | 727 | sb->s_blocksize_bits) |
| 740 | continue; | 728 | continue; |
| 741 | 729 | ||
| 742 | if (udf_check_anchor_block(sb, last[i], varconv)) { | 730 | if (udf_check_anchor_block(sb, last[i])) { |
| 743 | sbi->s_anchor[0] = last[i]; | 731 | sbi->s_anchor[0] = last[i]; |
| 744 | sbi->s_anchor[1] = last[i] - 256; | 732 | sbi->s_anchor[1] = last[i] - 256; |
| 745 | return last[i]; | 733 | return last[i]; |
| @@ -748,17 +736,17 @@ static sector_t udf_scan_anchors(struct super_block *sb, bool varconv, | |||
| 748 | if (last[i] < 256) | 736 | if (last[i] < 256) |
| 749 | continue; | 737 | continue; |
| 750 | 738 | ||
| 751 | if (udf_check_anchor_block(sb, last[i] - 256, varconv)) { | 739 | if (udf_check_anchor_block(sb, last[i] - 256)) { |
| 752 | sbi->s_anchor[1] = last[i] - 256; | 740 | sbi->s_anchor[1] = last[i] - 256; |
| 753 | return last[i]; | 741 | return last[i]; |
| 754 | } | 742 | } |
| 755 | } | 743 | } |
| 756 | 744 | ||
| 757 | if (udf_check_anchor_block(sb, sbi->s_session + 256, varconv)) { | 745 | if (udf_check_anchor_block(sb, sbi->s_session + 256)) { |
| 758 | sbi->s_anchor[0] = sbi->s_session + 256; | 746 | sbi->s_anchor[0] = sbi->s_session + 256; |
| 759 | return last[0]; | 747 | return last[0]; |
| 760 | } | 748 | } |
| 761 | if (udf_check_anchor_block(sb, sbi->s_session + 512, varconv)) { | 749 | if (udf_check_anchor_block(sb, sbi->s_session + 512)) { |
| 762 | sbi->s_anchor[0] = sbi->s_session + 512; | 750 | sbi->s_anchor[0] = sbi->s_session + 512; |
| 763 | return last[0]; | 751 | return last[0]; |
| 764 | } | 752 | } |
| @@ -780,23 +768,24 @@ static void udf_find_anchor(struct super_block *sb) | |||
| 780 | int i; | 768 | int i; |
| 781 | struct udf_sb_info *sbi = UDF_SB(sb); | 769 | struct udf_sb_info *sbi = UDF_SB(sb); |
| 782 | 770 | ||
| 783 | lastblock = udf_scan_anchors(sb, 0, sbi->s_last_block); | 771 | lastblock = udf_scan_anchors(sb, sbi->s_last_block); |
| 784 | if (lastblock) | 772 | if (lastblock) |
| 785 | goto check_anchor; | 773 | goto check_anchor; |
| 786 | 774 | ||
| 787 | /* No anchor found? Try VARCONV conversion of block numbers */ | 775 | /* No anchor found? Try VARCONV conversion of block numbers */ |
| 776 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
| 788 | /* Firstly, we try to not convert number of the last block */ | 777 | /* Firstly, we try to not convert number of the last block */ |
| 789 | lastblock = udf_scan_anchors(sb, 1, | 778 | lastblock = udf_scan_anchors(sb, |
| 790 | udf_variable_to_fixed(sbi->s_last_block)); | 779 | udf_variable_to_fixed(sbi->s_last_block)); |
| 791 | if (lastblock) { | 780 | if (lastblock) |
| 792 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
| 793 | goto check_anchor; | 781 | goto check_anchor; |
| 794 | } | ||
| 795 | 782 | ||
| 796 | /* Secondly, we try with converted number of the last block */ | 783 | /* Secondly, we try with converted number of the last block */ |
| 797 | lastblock = udf_scan_anchors(sb, 1, sbi->s_last_block); | 784 | lastblock = udf_scan_anchors(sb, sbi->s_last_block); |
| 798 | if (lastblock) | 785 | if (!lastblock) { |
| 799 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | 786 | /* VARCONV didn't help. Clear it. */ |
| 787 | UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); | ||
| 788 | } | ||
| 800 | 789 | ||
| 801 | check_anchor: | 790 | check_anchor: |
| 802 | /* | 791 | /* |
diff --git a/fs/utimes.c b/fs/utimes.c index af059d5cb485..b6b664e7145e 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
| @@ -40,14 +40,9 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times) | |||
| 40 | 40 | ||
| 41 | #endif | 41 | #endif |
| 42 | 42 | ||
| 43 | static bool nsec_special(long nsec) | ||
| 44 | { | ||
| 45 | return nsec == UTIME_OMIT || nsec == UTIME_NOW; | ||
| 46 | } | ||
| 47 | |||
| 48 | static bool nsec_valid(long nsec) | 43 | static bool nsec_valid(long nsec) |
| 49 | { | 44 | { |
| 50 | if (nsec_special(nsec)) | 45 | if (nsec == UTIME_OMIT || nsec == UTIME_NOW) |
| 51 | return true; | 46 | return true; |
| 52 | 47 | ||
| 53 | return nsec >= 0 && nsec <= 999999999; | 48 | return nsec >= 0 && nsec <= 999999999; |
| @@ -102,7 +97,11 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
| 102 | if (error) | 97 | if (error) |
| 103 | goto dput_and_out; | 98 | goto dput_and_out; |
| 104 | 99 | ||
| 105 | /* Don't worry, the checks are done in inode_change_ok() */ | 100 | if (times && times[0].tv_nsec == UTIME_NOW && |
| 101 | times[1].tv_nsec == UTIME_NOW) | ||
| 102 | times = NULL; | ||
| 103 | |||
| 104 | /* In most cases, the checks are done in inode_change_ok() */ | ||
| 106 | newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; | 105 | newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; |
| 107 | if (times) { | 106 | if (times) { |
| 108 | error = -EPERM; | 107 | error = -EPERM; |
| @@ -124,28 +123,34 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
| 124 | newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; | 123 | newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; |
| 125 | newattrs.ia_valid |= ATTR_MTIME_SET; | 124 | newattrs.ia_valid |= ATTR_MTIME_SET; |
| 126 | } | 125 | } |
| 127 | } | ||
| 128 | 126 | ||
| 129 | /* | 127 | /* |
| 130 | * If times is NULL or both times are either UTIME_OMIT or | 128 | * For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT |
| 131 | * UTIME_NOW, then need to check permissions, because | 129 | * cases, we need to make an extra check that is not done by |
| 132 | * inode_change_ok() won't do it. | 130 | * inode_change_ok(). |
| 133 | */ | 131 | */ |
| 134 | if (!times || (nsec_special(times[0].tv_nsec) && | 132 | if (((times[0].tv_nsec == UTIME_NOW && |
| 135 | nsec_special(times[1].tv_nsec))) { | 133 | times[1].tv_nsec == UTIME_OMIT) |
| 134 | || | ||
| 135 | (times[0].tv_nsec == UTIME_OMIT && | ||
| 136 | times[1].tv_nsec == UTIME_NOW)) | ||
| 137 | && !is_owner_or_cap(inode)) | ||
| 138 | goto mnt_drop_write_and_out; | ||
| 139 | } else { | ||
| 140 | |||
| 141 | /* | ||
| 142 | * If times is NULL (or both times are UTIME_NOW), | ||
| 143 | * then we need to check permissions, because | ||
| 144 | * inode_change_ok() won't do it. | ||
| 145 | */ | ||
| 136 | error = -EACCES; | 146 | error = -EACCES; |
| 137 | if (IS_IMMUTABLE(inode)) | 147 | if (IS_IMMUTABLE(inode)) |
| 138 | goto mnt_drop_write_and_out; | 148 | goto mnt_drop_write_and_out; |
| 139 | 149 | ||
| 140 | if (!is_owner_or_cap(inode)) { | 150 | if (!is_owner_or_cap(inode)) { |
| 141 | if (f) { | 151 | error = permission(inode, MAY_WRITE, NULL); |
| 142 | if (!(f->f_mode & FMODE_WRITE)) | 152 | if (error) |
| 143 | goto mnt_drop_write_and_out; | 153 | goto mnt_drop_write_and_out; |
| 144 | } else { | ||
| 145 | error = vfs_permission(&nd, MAY_WRITE); | ||
| 146 | if (error) | ||
| 147 | goto mnt_drop_write_and_out; | ||
| 148 | } | ||
| 149 | } | 154 | } |
| 150 | } | 155 | } |
| 151 | mutex_lock(&inode->i_mutex); | 156 | mutex_lock(&inode->i_mutex); |
| @@ -169,14 +174,6 @@ asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __ | |||
| 169 | if (utimes) { | 174 | if (utimes) { |
| 170 | if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) | 175 | if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) |
| 171 | return -EFAULT; | 176 | return -EFAULT; |
| 172 | if ((tstimes[0].tv_nsec == UTIME_OMIT || | ||
| 173 | tstimes[0].tv_nsec == UTIME_NOW) && | ||
| 174 | tstimes[0].tv_sec != 0) | ||
| 175 | return -EINVAL; | ||
| 176 | if ((tstimes[1].tv_nsec == UTIME_OMIT || | ||
| 177 | tstimes[1].tv_nsec == UTIME_NOW) && | ||
| 178 | tstimes[1].tv_sec != 0) | ||
| 179 | return -EINVAL; | ||
| 180 | 177 | ||
| 181 | /* Nothing to do, we must not even check the path. */ | 178 | /* Nothing to do, we must not even check the path. */ |
| 182 | if (tstimes[0].tv_nsec == UTIME_OMIT && | 179 | if (tstimes[0].tv_nsec == UTIME_OMIT && |
