diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-25 18:05:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-03-25 18:05:57 -0400 |
commit | 3e79d97828841305e3369ad1e07cfed5bf5989ef (patch) | |
tree | d14264947e9bf1a72922060dfefd08693e550ebc | |
parent | b098d6726bbfb94c06d6e1097466187afddae61f (diff) | |
parent | b37199e626b31e1175fb06764c5d1d687723aac2 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs fixes from Al Viro:
"These four commits are obvious fixes (a couple of fdget_pos()-related
ones from Eric Biggers, prepend_name() fix, missing checks for false
negatives from __lookup_mnt() in fs/namei.c)"
For now I'm pulling just the four obvious fixes, there's another four
pending in Al's 'for-linus' branch wrt the mnt_hash list that were more
involved.
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
rcuwalk: recheck mount_lock after mountpoint crossing attempts
make prepend_name() work correctly when called with negative *buflen
vfs: Don't let __fdget_pos() get FMODE_PATH files
vfs: atomic f_pos access in llseek()
-rw-r--r-- | fs/dcache.c | 4 | ||||
-rw-r--r-- | fs/file.c | 19 | ||||
-rw-r--r-- | fs/namei.c | 29 | ||||
-rw-r--r-- | fs/read_write.c | 4 |
4 files changed, 21 insertions, 35 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index 265e0ce9769c..ca02c13a84aa 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -2833,9 +2833,9 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) | |||
2833 | u32 dlen = ACCESS_ONCE(name->len); | 2833 | u32 dlen = ACCESS_ONCE(name->len); |
2834 | char *p; | 2834 | char *p; |
2835 | 2835 | ||
2836 | if (*buflen < dlen + 1) | ||
2837 | return -ENAMETOOLONG; | ||
2838 | *buflen -= dlen + 1; | 2836 | *buflen -= dlen + 1; |
2837 | if (*buflen < 0) | ||
2838 | return -ENAMETOOLONG; | ||
2839 | p = *buffer -= dlen + 1; | 2839 | p = *buffer -= dlen + 1; |
2840 | *p++ = '/'; | 2840 | *p++ = '/'; |
2841 | while (dlen--) { | 2841 | while (dlen--) { |
@@ -713,27 +713,16 @@ unsigned long __fdget_raw(unsigned int fd) | |||
713 | 713 | ||
714 | unsigned long __fdget_pos(unsigned int fd) | 714 | unsigned long __fdget_pos(unsigned int fd) |
715 | { | 715 | { |
716 | struct files_struct *files = current->files; | 716 | unsigned long v = __fdget(fd); |
717 | struct file *file; | 717 | struct file *file = (struct file *)(v & ~3); |
718 | unsigned long v; | ||
719 | |||
720 | if (atomic_read(&files->count) == 1) { | ||
721 | file = __fcheck_files(files, fd); | ||
722 | v = 0; | ||
723 | } else { | ||
724 | file = __fget(fd, 0); | ||
725 | v = FDPUT_FPUT; | ||
726 | } | ||
727 | if (!file) | ||
728 | return 0; | ||
729 | 718 | ||
730 | if (file->f_mode & FMODE_ATOMIC_POS) { | 719 | if (file && (file->f_mode & FMODE_ATOMIC_POS)) { |
731 | if (file_count(file) > 1) { | 720 | if (file_count(file) > 1) { |
732 | v |= FDPUT_POS_UNLOCK; | 721 | v |= FDPUT_POS_UNLOCK; |
733 | mutex_lock(&file->f_pos_lock); | 722 | mutex_lock(&file->f_pos_lock); |
734 | } | 723 | } |
735 | } | 724 | } |
736 | return v | (unsigned long)file; | 725 | return v; |
737 | } | 726 | } |
738 | 727 | ||
739 | /* | 728 | /* |
diff --git a/fs/namei.c b/fs/namei.c index 2f730ef9b4b3..4b491b431990 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1109,7 +1109,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1109 | return false; | 1109 | return false; |
1110 | 1110 | ||
1111 | if (!d_mountpoint(path->dentry)) | 1111 | if (!d_mountpoint(path->dentry)) |
1112 | break; | 1112 | return true; |
1113 | 1113 | ||
1114 | mounted = __lookup_mnt(path->mnt, path->dentry); | 1114 | mounted = __lookup_mnt(path->mnt, path->dentry); |
1115 | if (!mounted) | 1115 | if (!mounted) |
@@ -1125,20 +1125,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, | |||
1125 | */ | 1125 | */ |
1126 | *inode = path->dentry->d_inode; | 1126 | *inode = path->dentry->d_inode; |
1127 | } | 1127 | } |
1128 | return true; | 1128 | return read_seqretry(&mount_lock, nd->m_seq); |
1129 | } | ||
1130 | |||
1131 | static void follow_mount_rcu(struct nameidata *nd) | ||
1132 | { | ||
1133 | while (d_mountpoint(nd->path.dentry)) { | ||
1134 | struct mount *mounted; | ||
1135 | mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry); | ||
1136 | if (!mounted) | ||
1137 | break; | ||
1138 | nd->path.mnt = &mounted->mnt; | ||
1139 | nd->path.dentry = mounted->mnt.mnt_root; | ||
1140 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1141 | } | ||
1142 | } | 1129 | } |
1143 | 1130 | ||
1144 | static int follow_dotdot_rcu(struct nameidata *nd) | 1131 | static int follow_dotdot_rcu(struct nameidata *nd) |
@@ -1166,7 +1153,17 @@ static int follow_dotdot_rcu(struct nameidata *nd) | |||
1166 | break; | 1153 | break; |
1167 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | 1154 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); |
1168 | } | 1155 | } |
1169 | follow_mount_rcu(nd); | 1156 | while (d_mountpoint(nd->path.dentry)) { |
1157 | struct mount *mounted; | ||
1158 | mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry); | ||
1159 | if (!mounted) | ||
1160 | break; | ||
1161 | nd->path.mnt = &mounted->mnt; | ||
1162 | nd->path.dentry = mounted->mnt.mnt_root; | ||
1163 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1164 | if (!read_seqretry(&mount_lock, nd->m_seq)) | ||
1165 | goto failed; | ||
1166 | } | ||
1170 | nd->inode = nd->path.dentry->d_inode; | 1167 | nd->inode = nd->path.dentry->d_inode; |
1171 | return 0; | 1168 | return 0; |
1172 | 1169 | ||
diff --git a/fs/read_write.c b/fs/read_write.c index 54e19b9392dc..28cc9c810744 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -307,7 +307,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, | |||
307 | unsigned int, whence) | 307 | unsigned int, whence) |
308 | { | 308 | { |
309 | int retval; | 309 | int retval; |
310 | struct fd f = fdget(fd); | 310 | struct fd f = fdget_pos(fd); |
311 | loff_t offset; | 311 | loff_t offset; |
312 | 312 | ||
313 | if (!f.file) | 313 | if (!f.file) |
@@ -327,7 +327,7 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, | |||
327 | retval = 0; | 327 | retval = 0; |
328 | } | 328 | } |
329 | out_putf: | 329 | out_putf: |
330 | fdput(f); | 330 | fdput_pos(f); |
331 | return retval; | 331 | return retval; |
332 | } | 332 | } |
333 | #endif | 333 | #endif |