aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-18 12:03:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-18 12:03:15 -0400
commitd36c30181c4cf6ead34ae30fa2c777b871225c87 (patch)
tree8a2476c0eb6bb83ed5a8b493d79458d0e114a146
parenta406721dff91a9a5297d140dbb90327966cf9bc0 (diff)
parent0916a5e45fbd2604a303c8cc18e6b2b7c815e4c9 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: hppfs_lookup(): don't open-code lookup_one_len() hppfs: fix dentry leak cramfs: get_cramfs_inode() returns ERR_PTR() on failure ufs should use d_splice_alias() fix exofs ->get_parent() ceph analog of cifs build_path_from_dentry() race fix cifs: build_path_from_dentry() race fix
-rw-r--r--fs/ceph/mds_client.c19
-rw-r--r--fs/cifs/dir.c13
-rw-r--r--fs/cramfs/inode.c22
-rw-r--r--fs/exofs/super.c2
-rw-r--r--fs/hppfs/hppfs.c31
-rw-r--r--fs/ufs/namei.c12
6 files changed, 54 insertions, 45 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 79743d146be6..0c1d91756528 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
1438 struct dentry *temp; 1438 struct dentry *temp;
1439 char *path; 1439 char *path;
1440 int len, pos; 1440 int len, pos;
1441 unsigned seq;
1441 1442
1442 if (dentry == NULL) 1443 if (dentry == NULL)
1443 return ERR_PTR(-EINVAL); 1444 return ERR_PTR(-EINVAL);
1444 1445
1445retry: 1446retry:
1446 len = 0; 1447 len = 0;
1448 seq = read_seqbegin(&rename_lock);
1449 rcu_read_lock();
1447 for (temp = dentry; !IS_ROOT(temp);) { 1450 for (temp = dentry; !IS_ROOT(temp);) {
1448 struct inode *inode = temp->d_inode; 1451 struct inode *inode = temp->d_inode;
1449 if (inode && ceph_snap(inode) == CEPH_SNAPDIR) 1452 if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
@@ -1455,10 +1458,12 @@ retry:
1455 len += 1 + temp->d_name.len; 1458 len += 1 + temp->d_name.len;
1456 temp = temp->d_parent; 1459 temp = temp->d_parent;
1457 if (temp == NULL) { 1460 if (temp == NULL) {
1461 rcu_read_unlock();
1458 pr_err("build_path corrupt dentry %p\n", dentry); 1462 pr_err("build_path corrupt dentry %p\n", dentry);
1459 return ERR_PTR(-EINVAL); 1463 return ERR_PTR(-EINVAL);
1460 } 1464 }
1461 } 1465 }
1466 rcu_read_unlock();
1462 if (len) 1467 if (len)
1463 len--; /* no leading '/' */ 1468 len--; /* no leading '/' */
1464 1469
@@ -1467,9 +1472,12 @@ retry:
1467 return ERR_PTR(-ENOMEM); 1472 return ERR_PTR(-ENOMEM);
1468 pos = len; 1473 pos = len;
1469 path[pos] = 0; /* trailing null */ 1474 path[pos] = 0; /* trailing null */
1475 rcu_read_lock();
1470 for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) { 1476 for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
1471 struct inode *inode = temp->d_inode; 1477 struct inode *inode;
1472 1478
1479 spin_lock(&temp->d_lock);
1480 inode = temp->d_inode;
1473 if (inode && ceph_snap(inode) == CEPH_SNAPDIR) { 1481 if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
1474 dout("build_path path+%d: %p SNAPDIR\n", 1482 dout("build_path path+%d: %p SNAPDIR\n",
1475 pos, temp); 1483 pos, temp);
@@ -1478,21 +1486,26 @@ retry:
1478 break; 1486 break;
1479 } else { 1487 } else {
1480 pos -= temp->d_name.len; 1488 pos -= temp->d_name.len;
1481 if (pos < 0) 1489 if (pos < 0) {
1490 spin_unlock(&temp->d_lock);
1482 break; 1491 break;
1492 }
1483 strncpy(path + pos, temp->d_name.name, 1493 strncpy(path + pos, temp->d_name.name,
1484 temp->d_name.len); 1494 temp->d_name.len);
1485 } 1495 }
1496 spin_unlock(&temp->d_lock);
1486 if (pos) 1497 if (pos)
1487 path[--pos] = '/'; 1498 path[--pos] = '/';
1488 temp = temp->d_parent; 1499 temp = temp->d_parent;
1489 if (temp == NULL) { 1500 if (temp == NULL) {
1501 rcu_read_unlock();
1490 pr_err("build_path corrupt dentry\n"); 1502 pr_err("build_path corrupt dentry\n");
1491 kfree(path); 1503 kfree(path);
1492 return ERR_PTR(-EINVAL); 1504 return ERR_PTR(-EINVAL);
1493 } 1505 }
1494 } 1506 }
1495 if (pos != 0) { 1507 rcu_read_unlock();
1508 if (pos != 0 || read_seqretry(&rename_lock, seq)) {
1496 pr_err("build_path did not end path lookup where " 1509 pr_err("build_path did not end path lookup where "
1497 "expected, namelen is %d, pos is %d\n", len, pos); 1510 "expected, namelen is %d, pos is %d\n", len, pos);
1498 /* presumably this is only possible if racing with a 1511 /* presumably this is only possible if racing with a
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 81914df47ef1..fa8c21d913bc 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry)
55 char dirsep; 55 char dirsep;
56 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); 56 struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
57 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb); 57 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
58 unsigned seq;
58 59
59 if (direntry == NULL) 60 if (direntry == NULL)
60 return NULL; /* not much we can do if dentry is freed and 61 return NULL; /* not much we can do if dentry is freed and
@@ -68,22 +69,29 @@ build_path_from_dentry(struct dentry *direntry)
68 dfsplen = 0; 69 dfsplen = 0;
69cifs_bp_rename_retry: 70cifs_bp_rename_retry:
70 namelen = dfsplen; 71 namelen = dfsplen;
72 seq = read_seqbegin(&rename_lock);
73 rcu_read_lock();
71 for (temp = direntry; !IS_ROOT(temp);) { 74 for (temp = direntry; !IS_ROOT(temp);) {
72 namelen += (1 + temp->d_name.len); 75 namelen += (1 + temp->d_name.len);
73 temp = temp->d_parent; 76 temp = temp->d_parent;
74 if (temp == NULL) { 77 if (temp == NULL) {
75 cERROR(1, "corrupt dentry"); 78 cERROR(1, "corrupt dentry");
79 rcu_read_unlock();
76 return NULL; 80 return NULL;
77 } 81 }
78 } 82 }
83 rcu_read_unlock();
79 84
80 full_path = kmalloc(namelen+1, GFP_KERNEL); 85 full_path = kmalloc(namelen+1, GFP_KERNEL);
81 if (full_path == NULL) 86 if (full_path == NULL)
82 return full_path; 87 return full_path;
83 full_path[namelen] = 0; /* trailing null */ 88 full_path[namelen] = 0; /* trailing null */
89 rcu_read_lock();
84 for (temp = direntry; !IS_ROOT(temp);) { 90 for (temp = direntry; !IS_ROOT(temp);) {
91 spin_lock(&temp->d_lock);
85 namelen -= 1 + temp->d_name.len; 92 namelen -= 1 + temp->d_name.len;
86 if (namelen < 0) { 93 if (namelen < 0) {
94 spin_unlock(&temp->d_lock);
87 break; 95 break;
88 } else { 96 } else {
89 full_path[namelen] = dirsep; 97 full_path[namelen] = dirsep;
@@ -91,14 +99,17 @@ cifs_bp_rename_retry:
91 temp->d_name.len); 99 temp->d_name.len);
92 cFYI(0, "name: %s", full_path + namelen); 100 cFYI(0, "name: %s", full_path + namelen);
93 } 101 }
102 spin_unlock(&temp->d_lock);
94 temp = temp->d_parent; 103 temp = temp->d_parent;
95 if (temp == NULL) { 104 if (temp == NULL) {
96 cERROR(1, "corrupt dentry"); 105 cERROR(1, "corrupt dentry");
106 rcu_read_unlock();
97 kfree(full_path); 107 kfree(full_path);
98 return NULL; 108 return NULL;
99 } 109 }
100 } 110 }
101 if (namelen != dfsplen) { 111 rcu_read_unlock();
112 if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
102 cERROR(1, "did not end path lookup where expected namelen is %d", 113 cERROR(1, "did not end path lookup where expected namelen is %d",
103 namelen); 114 namelen);
104 /* presumably this is only possible if racing with a rename 115 /* presumably this is only possible if racing with a rename
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index e141939080f0..739fb59bcdc2 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -37,7 +37,7 @@ static DEFINE_MUTEX(read_mutex);
37/* These macros may change in future, to provide better st_ino semantics. */ 37/* These macros may change in future, to provide better st_ino semantics. */
38#define OFFSET(x) ((x)->i_ino) 38#define OFFSET(x) ((x)->i_ino)
39 39
40static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) 40static unsigned long cramino(const struct cramfs_inode *cino, unsigned int offset)
41{ 41{
42 if (!cino->offset) 42 if (!cino->offset)
43 return offset + 1; 43 return offset + 1;
@@ -61,7 +61,7 @@ static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset)
61} 61}
62 62
63static struct inode *get_cramfs_inode(struct super_block *sb, 63static struct inode *get_cramfs_inode(struct super_block *sb,
64 struct cramfs_inode *cramfs_inode, unsigned int offset) 64 const struct cramfs_inode *cramfs_inode, unsigned int offset)
65{ 65{
66 struct inode *inode; 66 struct inode *inode;
67 static struct timespec zerotime; 67 static struct timespec zerotime;
@@ -317,7 +317,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
317 /* Set it all up.. */ 317 /* Set it all up.. */
318 sb->s_op = &cramfs_ops; 318 sb->s_op = &cramfs_ops;
319 root = get_cramfs_inode(sb, &super.root, 0); 319 root = get_cramfs_inode(sb, &super.root, 0);
320 if (!root) 320 if (IS_ERR(root))
321 goto out; 321 goto out;
322 sb->s_root = d_alloc_root(root); 322 sb->s_root = d_alloc_root(root);
323 if (!sb->s_root) { 323 if (!sb->s_root) {
@@ -423,6 +423,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
423static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 423static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
424{ 424{
425 unsigned int offset = 0; 425 unsigned int offset = 0;
426 struct inode *inode = NULL;
426 int sorted; 427 int sorted;
427 428
428 mutex_lock(&read_mutex); 429 mutex_lock(&read_mutex);
@@ -449,8 +450,8 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
449 450
450 for (;;) { 451 for (;;) {
451 if (!namelen) { 452 if (!namelen) {
452 mutex_unlock(&read_mutex); 453 inode = ERR_PTR(-EIO);
453 return ERR_PTR(-EIO); 454 goto out;
454 } 455 }
455 if (name[namelen-1]) 456 if (name[namelen-1])
456 break; 457 break;
@@ -462,17 +463,18 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
462 if (retval > 0) 463 if (retval > 0)
463 continue; 464 continue;
464 if (!retval) { 465 if (!retval) {
465 struct cramfs_inode entry = *de; 466 inode = get_cramfs_inode(dir->i_sb, de, dir_off);
466 mutex_unlock(&read_mutex); 467 break;
467 d_add(dentry, get_cramfs_inode(dir->i_sb, &entry, dir_off));
468 return NULL;
469 } 468 }
470 /* else (retval < 0) */ 469 /* else (retval < 0) */
471 if (sorted) 470 if (sorted)
472 break; 471 break;
473 } 472 }
473out:
474 mutex_unlock(&read_mutex); 474 mutex_unlock(&read_mutex);
475 d_add(dentry, NULL); 475 if (IS_ERR(inode))
476 return ERR_CAST(inode);
477 d_add(dentry, inode);
476 return NULL; 478 return NULL;
477} 479}
478 480
diff --git a/fs/exofs/super.c b/fs/exofs/super.c
index 06065bd37fc3..c57beddcc217 100644
--- a/fs/exofs/super.c
+++ b/fs/exofs/super.c
@@ -913,7 +913,7 @@ struct dentry *exofs_get_parent(struct dentry *child)
913 unsigned long ino = exofs_parent_ino(child); 913 unsigned long ino = exofs_parent_ino(child);
914 914
915 if (!ino) 915 if (!ino)
916 return NULL; 916 return ERR_PTR(-ESTALE);
917 917
918 return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino)); 918 return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
919} 919}
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 87ed48e0343d..85c098a499f3 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -139,7 +139,8 @@ static int file_removed(struct dentry *dentry, const char *file)
139static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, 139static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
140 struct nameidata *nd) 140 struct nameidata *nd)
141{ 141{
142 struct dentry *proc_dentry, *new, *parent; 142 struct dentry *proc_dentry, *parent;
143 struct qstr *name = &dentry->d_name;
143 struct inode *inode; 144 struct inode *inode;
144 int err, deleted; 145 int err, deleted;
145 146
@@ -149,23 +150,9 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
149 else if (deleted) 150 else if (deleted)
150 return ERR_PTR(-ENOENT); 151 return ERR_PTR(-ENOENT);
151 152
152 err = -ENOMEM;
153 parent = HPPFS_I(ino)->proc_dentry; 153 parent = HPPFS_I(ino)->proc_dentry;
154 mutex_lock(&parent->d_inode->i_mutex); 154 mutex_lock(&parent->d_inode->i_mutex);
155 proc_dentry = d_lookup(parent, &dentry->d_name); 155 proc_dentry = lookup_one_len(name->name, parent, name->len);
156 if (proc_dentry == NULL) {
157 proc_dentry = d_alloc(parent, &dentry->d_name);
158 if (proc_dentry == NULL) {
159 mutex_unlock(&parent->d_inode->i_mutex);
160 goto out;
161 }
162 new = (*parent->d_inode->i_op->lookup)(parent->d_inode,
163 proc_dentry, NULL);
164 if (new) {
165 dput(proc_dentry);
166 proc_dentry = new;
167 }
168 }
169 mutex_unlock(&parent->d_inode->i_mutex); 156 mutex_unlock(&parent->d_inode->i_mutex);
170 157
171 if (IS_ERR(proc_dentry)) 158 if (IS_ERR(proc_dentry))
@@ -174,13 +161,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
174 err = -ENOMEM; 161 err = -ENOMEM;
175 inode = get_inode(ino->i_sb, proc_dentry); 162 inode = get_inode(ino->i_sb, proc_dentry);
176 if (!inode) 163 if (!inode)
177 goto out_dput; 164 goto out;
178 165
179 d_add(dentry, inode); 166 d_add(dentry, inode);
180 return NULL; 167 return NULL;
181 168
182 out_dput:
183 dput(proc_dentry);
184 out: 169 out:
185 return ERR_PTR(err); 170 return ERR_PTR(err);
186} 171}
@@ -690,8 +675,10 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
690 struct inode *proc_ino = dentry->d_inode; 675 struct inode *proc_ino = dentry->d_inode;
691 struct inode *inode = new_inode(sb); 676 struct inode *inode = new_inode(sb);
692 677
693 if (!inode) 678 if (!inode) {
679 dput(dentry);
694 return ERR_PTR(-ENOMEM); 680 return ERR_PTR(-ENOMEM);
681 }
695 682
696 if (S_ISDIR(dentry->d_inode->i_mode)) { 683 if (S_ISDIR(dentry->d_inode->i_mode)) {
697 inode->i_op = &hppfs_dir_iops; 684 inode->i_op = &hppfs_dir_iops;
@@ -704,7 +691,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
704 inode->i_fop = &hppfs_file_fops; 691 inode->i_fop = &hppfs_file_fops;
705 } 692 }
706 693
707 HPPFS_I(inode)->proc_dentry = dget(dentry); 694 HPPFS_I(inode)->proc_dentry = dentry;
708 695
709 inode->i_uid = proc_ino->i_uid; 696 inode->i_uid = proc_ino->i_uid;
710 inode->i_gid = proc_ino->i_gid; 697 inode->i_gid = proc_ino->i_gid;
@@ -737,7 +724,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
737 sb->s_fs_info = proc_mnt; 724 sb->s_fs_info = proc_mnt;
738 725
739 err = -ENOMEM; 726 err = -ENOMEM;
740 root_inode = get_inode(sb, proc_mnt->mnt_sb->s_root); 727 root_inode = get_inode(sb, dget(proc_mnt->mnt_sb->s_root));
741 if (!root_inode) 728 if (!root_inode)
742 goto out_mntput; 729 goto out_mntput;
743 730
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 29309e25417f..b57aab9a1184 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -56,16 +56,12 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
56 56
57 lock_ufs(dir->i_sb); 57 lock_ufs(dir->i_sb);
58 ino = ufs_inode_by_name(dir, &dentry->d_name); 58 ino = ufs_inode_by_name(dir, &dentry->d_name);
59 if (ino) { 59 if (ino)
60 inode = ufs_iget(dir->i_sb, ino); 60 inode = ufs_iget(dir->i_sb, ino);
61 if (IS_ERR(inode)) {
62 unlock_ufs(dir->i_sb);
63 return ERR_CAST(inode);
64 }
65 }
66 unlock_ufs(dir->i_sb); 61 unlock_ufs(dir->i_sb);
67 d_add(dentry, inode); 62 if (IS_ERR(inode))
68 return NULL; 63 return ERR_CAST(inode);
64 return d_splice_alias(inode, dentry);
69} 65}
70 66
71/* 67/*