diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-18 12:03:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-18 12:03:15 -0400 |
commit | d36c30181c4cf6ead34ae30fa2c777b871225c87 (patch) | |
tree | 8a2476c0eb6bb83ed5a8b493d79458d0e114a146 | |
parent | a406721dff91a9a5297d140dbb90327966cf9bc0 (diff) | |
parent | 0916a5e45fbd2604a303c8cc18e6b2b7c815e4c9 (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.c | 19 | ||||
-rw-r--r-- | fs/cifs/dir.c | 13 | ||||
-rw-r--r-- | fs/cramfs/inode.c | 22 | ||||
-rw-r--r-- | fs/exofs/super.c | 2 | ||||
-rw-r--r-- | fs/hppfs/hppfs.c | 31 | ||||
-rw-r--r-- | fs/ufs/namei.c | 12 |
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 | ||
1445 | retry: | 1446 | retry: |
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; |
69 | cifs_bp_rename_retry: | 70 | cifs_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 | ||
40 | static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) | 40 | static 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 | ||
63 | static struct inode *get_cramfs_inode(struct super_block *sb, | 63 | static 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) | |||
423 | static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 423 | static 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 | } |
473 | out: | ||
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) | |||
139 | static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, | 139 | static 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 | /* |