Skip to content

Commit d36c301

Browse files
committed
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
2 parents a406721 + 0916a5e commit d36c301

File tree

6 files changed

+54
-45
lines changed

6 files changed

+54
-45
lines changed

fs/ceph/mds_client.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,12 +1438,15 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
14381438
struct dentry *temp;
14391439
char *path;
14401440
int len, pos;
1441+
unsigned seq;
14411442

14421443
if (dentry == NULL)
14431444
return ERR_PTR(-EINVAL);
14441445

14451446
retry:
14461447
len = 0;
1448+
seq = read_seqbegin(&rename_lock);
1449+
rcu_read_lock();
14471450
for (temp = dentry; !IS_ROOT(temp);) {
14481451
struct inode *inode = temp->d_inode;
14491452
if (inode && ceph_snap(inode) == CEPH_SNAPDIR)
@@ -1455,10 +1458,12 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
14551458
len += 1 + temp->d_name.len;
14561459
temp = temp->d_parent;
14571460
if (temp == NULL) {
1461+
rcu_read_unlock();
14581462
pr_err("build_path corrupt dentry %p\n", dentry);
14591463
return ERR_PTR(-EINVAL);
14601464
}
14611465
}
1466+
rcu_read_unlock();
14621467
if (len)
14631468
len--; /* no leading '/' */
14641469

@@ -1467,9 +1472,12 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
14671472
return ERR_PTR(-ENOMEM);
14681473
pos = len;
14691474
path[pos] = 0; /* trailing null */
1475+
rcu_read_lock();
14701476
for (temp = dentry; !IS_ROOT(temp) && pos != 0; ) {
1471-
struct inode *inode = temp->d_inode;
1477+
struct inode *inode;
14721478

1479+
spin_lock(&temp->d_lock);
1480+
inode = temp->d_inode;
14731481
if (inode && ceph_snap(inode) == CEPH_SNAPDIR) {
14741482
dout("build_path path+%d: %p SNAPDIR\n",
14751483
pos, temp);
@@ -1478,21 +1486,26 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int *plen, u64 *base,
14781486
break;
14791487
} else {
14801488
pos -= temp->d_name.len;
1481-
if (pos < 0)
1489+
if (pos < 0) {
1490+
spin_unlock(&temp->d_lock);
14821491
break;
1492+
}
14831493
strncpy(path + pos, temp->d_name.name,
14841494
temp->d_name.len);
14851495
}
1496+
spin_unlock(&temp->d_lock);
14861497
if (pos)
14871498
path[--pos] = '/';
14881499
temp = temp->d_parent;
14891500
if (temp == NULL) {
1501+
rcu_read_unlock();
14901502
pr_err("build_path corrupt dentry\n");
14911503
kfree(path);
14921504
return ERR_PTR(-EINVAL);
14931505
}
14941506
}
1495-
if (pos != 0) {
1507+
rcu_read_unlock();
1508+
if (pos != 0 || read_seqretry(&rename_lock, seq)) {
14961509
pr_err("build_path did not end path lookup where "
14971510
"expected, namelen is %d, pos is %d\n", len, pos);
14981511
/* presumably this is only possible if racing with a

fs/cifs/dir.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ build_path_from_dentry(struct dentry *direntry)
5555
char dirsep;
5656
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
5757
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
58+
unsigned seq;
5859

5960
if (direntry == NULL)
6061
return NULL; /* not much we can do if dentry is freed and
@@ -68,37 +69,47 @@ build_path_from_dentry(struct dentry *direntry)
6869
dfsplen = 0;
6970
cifs_bp_rename_retry:
7071
namelen = dfsplen;
72+
seq = read_seqbegin(&rename_lock);
73+
rcu_read_lock();
7174
for (temp = direntry; !IS_ROOT(temp);) {
7275
namelen += (1 + temp->d_name.len);
7376
temp = temp->d_parent;
7477
if (temp == NULL) {
7578
cERROR(1, "corrupt dentry");
79+
rcu_read_unlock();
7680
return NULL;
7781
}
7882
}
83+
rcu_read_unlock();
7984

8085
full_path = kmalloc(namelen+1, GFP_KERNEL);
8186
if (full_path == NULL)
8287
return full_path;
8388
full_path[namelen] = 0; /* trailing null */
89+
rcu_read_lock();
8490
for (temp = direntry; !IS_ROOT(temp);) {
91+
spin_lock(&temp->d_lock);
8592
namelen -= 1 + temp->d_name.len;
8693
if (namelen < 0) {
94+
spin_unlock(&temp->d_lock);
8795
break;
8896
} else {
8997
full_path[namelen] = dirsep;
9098
strncpy(full_path + namelen + 1, temp->d_name.name,
9199
temp->d_name.len);
92100
cFYI(0, "name: %s", full_path + namelen);
93101
}
102+
spin_unlock(&temp->d_lock);
94103
temp = temp->d_parent;
95104
if (temp == NULL) {
96105
cERROR(1, "corrupt dentry");
106+
rcu_read_unlock();
97107
kfree(full_path);
98108
return NULL;
99109
}
100110
}
101-
if (namelen != dfsplen) {
111+
rcu_read_unlock();
112+
if (namelen != dfsplen || read_seqretry(&rename_lock, seq)) {
102113
cERROR(1, "did not end path lookup where expected namelen is %d",
103114
namelen);
104115
/* presumably this is only possible if racing with a rename

fs/cramfs/inode.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static DEFINE_MUTEX(read_mutex);
3737
/* These macros may change in future, to provide better st_ino semantics. */
3838
#define OFFSET(x) ((x)->i_ino)
3939

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)
4141
{
4242
if (!cino->offset)
4343
return offset + 1;
@@ -61,7 +61,7 @@ static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset)
6161
}
6262

6363
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)
6565
{
6666
struct inode *inode;
6767
static struct timespec zerotime;
@@ -317,7 +317,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
317317
/* Set it all up.. */
318318
sb->s_op = &cramfs_ops;
319319
root = get_cramfs_inode(sb, &super.root, 0);
320-
if (!root)
320+
if (IS_ERR(root))
321321
goto out;
322322
sb->s_root = d_alloc_root(root);
323323
if (!sb->s_root) {
@@ -423,6 +423,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
423423
static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
424424
{
425425
unsigned int offset = 0;
426+
struct inode *inode = NULL;
426427
int sorted;
427428

428429
mutex_lock(&read_mutex);
@@ -449,8 +450,8 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
449450

450451
for (;;) {
451452
if (!namelen) {
452-
mutex_unlock(&read_mutex);
453-
return ERR_PTR(-EIO);
453+
inode = ERR_PTR(-EIO);
454+
goto out;
454455
}
455456
if (name[namelen-1])
456457
break;
@@ -462,17 +463,18 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s
462463
if (retval > 0)
463464
continue;
464465
if (!retval) {
465-
struct cramfs_inode entry = *de;
466-
mutex_unlock(&read_mutex);
467-
d_add(dentry, get_cramfs_inode(dir->i_sb, &entry, dir_off));
468-
return NULL;
466+
inode = get_cramfs_inode(dir->i_sb, de, dir_off);
467+
break;
469468
}
470469
/* else (retval < 0) */
471470
if (sorted)
472471
break;
473472
}
473+
out:
474474
mutex_unlock(&read_mutex);
475-
d_add(dentry, NULL);
475+
if (IS_ERR(inode))
476+
return ERR_CAST(inode);
477+
d_add(dentry, inode);
476478
return NULL;
477479
}
478480

fs/exofs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ struct dentry *exofs_get_parent(struct dentry *child)
913913
unsigned long ino = exofs_parent_ino(child);
914914

915915
if (!ino)
916-
return NULL;
916+
return ERR_PTR(-ESTALE);
917917

918918
return d_obtain_alias(exofs_iget(child->d_inode->i_sb, ino));
919919
}

fs/hppfs/hppfs.c

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,8 @@ static int file_removed(struct dentry *dentry, const char *file)
139139
static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
140140
struct nameidata *nd)
141141
{
142-
struct dentry *proc_dentry, *new, *parent;
142+
struct dentry *proc_dentry, *parent;
143+
struct qstr *name = &dentry->d_name;
143144
struct inode *inode;
144145
int err, deleted;
145146

@@ -149,23 +150,9 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
149150
else if (deleted)
150151
return ERR_PTR(-ENOENT);
151152

152-
err = -ENOMEM;
153153
parent = HPPFS_I(ino)->proc_dentry;
154154
mutex_lock(&parent->d_inode->i_mutex);
155-
proc_dentry = d_lookup(parent, &dentry->d_name);
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-
}
155+
proc_dentry = lookup_one_len(name->name, parent, name->len);
169156
mutex_unlock(&parent->d_inode->i_mutex);
170157

171158
if (IS_ERR(proc_dentry))
@@ -174,13 +161,11 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
174161
err = -ENOMEM;
175162
inode = get_inode(ino->i_sb, proc_dentry);
176163
if (!inode)
177-
goto out_dput;
164+
goto out;
178165

179166
d_add(dentry, inode);
180167
return NULL;
181168

182-
out_dput:
183-
dput(proc_dentry);
184169
out:
185170
return ERR_PTR(err);
186171
}
@@ -690,8 +675,10 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
690675
struct inode *proc_ino = dentry->d_inode;
691676
struct inode *inode = new_inode(sb);
692677

693-
if (!inode)
678+
if (!inode) {
679+
dput(dentry);
694680
return ERR_PTR(-ENOMEM);
681+
}
695682

696683
if (S_ISDIR(dentry->d_inode->i_mode)) {
697684
inode->i_op = &hppfs_dir_iops;
@@ -704,7 +691,7 @@ static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
704691
inode->i_fop = &hppfs_file_fops;
705692
}
706693

707-
HPPFS_I(inode)->proc_dentry = dget(dentry);
694+
HPPFS_I(inode)->proc_dentry = dentry;
708695

709696
inode->i_uid = proc_ino->i_uid;
710697
inode->i_gid = proc_ino->i_gid;
@@ -737,7 +724,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
737724
sb->s_fs_info = proc_mnt;
738725

739726
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));
741728
if (!root_inode)
742729
goto out_mntput;
743730

fs/ufs/namei.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,12 @@ static struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry, stru
5656

5757
lock_ufs(dir->i_sb);
5858
ino = ufs_inode_by_name(dir, &dentry->d_name);
59-
if (ino) {
59+
if (ino)
6060
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-
}
6661
unlock_ufs(dir->i_sb);
67-
d_add(dentry, inode);
68-
return NULL;
62+
if (IS_ERR(inode))
63+
return ERR_CAST(inode);
64+
return d_splice_alias(inode, dentry);
6965
}
7066

7167
/*

0 commit comments

Comments
 (0)