aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-03-25 18:05:57 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-03-25 18:05:57 -0400
commit3e79d97828841305e3369ad1e07cfed5bf5989ef (patch)
treed14264947e9bf1a72922060dfefd08693e550ebc
parentb098d6726bbfb94c06d6e1097466187afddae61f (diff)
parentb37199e626b31e1175fb06764c5d1d687723aac2 (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.c4
-rw-r--r--fs/file.c19
-rw-r--r--fs/namei.c29
-rw-r--r--fs/read_write.c4
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--) {
diff --git a/fs/file.c b/fs/file.c
index 60a45e9f5323..eb56a13dab3e 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -713,27 +713,16 @@ unsigned long __fdget_raw(unsigned int fd)
713 713
714unsigned long __fdget_pos(unsigned int fd) 714unsigned 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
1131static 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
1144static int follow_dotdot_rcu(struct nameidata *nd) 1131static 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 }
329out_putf: 329out_putf:
330 fdput(f); 330 fdput_pos(f);
331 return retval; 331 return retval;
332} 332}
333#endif 333#endif