diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-07 15:03:58 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-20 01:44:17 -0400 |
commit | a4464dbc0ca6a3ab8e9d1206bc05059dae2a559d (patch) | |
tree | d3c9332ab72cf5a4eba483ba1ff83c54ca4c42a0 | |
parent | e3c3d9c838d48c0341c40ea45ee087e3d8c8ea39 (diff) |
Make ->d_sb assign-once and always non-NULL
New helper (non-exported, fs/internal.h-only): __d_alloc(sb, name).
Allocates dentry, sets its ->d_sb to given superblock and sets
->d_op accordingly. Old d_alloc(NULL, name) callers are converted
to that (all of them know what superblock they want). d_alloc()
itself is left only for parent != NULl case; uses __d_alloc(),
inserts result into the list of parent's children.
Note that now ->d_sb is assign-once and never NULL *and*
->d_parent is never NULL either.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/dcache.c | 75 | ||||
-rw-r--r-- | fs/internal.h | 5 | ||||
-rw-r--r-- | fs/libfs.c | 6 |
3 files changed, 47 insertions, 39 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d3902139b533..c61edd0318c3 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -1275,8 +1275,8 @@ static struct shrinker dcache_shrinker = { | |||
1275 | }; | 1275 | }; |
1276 | 1276 | ||
1277 | /** | 1277 | /** |
1278 | * d_alloc - allocate a dcache entry | 1278 | * __d_alloc - allocate a dcache entry |
1279 | * @parent: parent of entry to allocate | 1279 | * @sb: filesystem it will belong to |
1280 | * @name: qstr of the name | 1280 | * @name: qstr of the name |
1281 | * | 1281 | * |
1282 | * Allocates a dentry. It returns %NULL if there is insufficient memory | 1282 | * Allocates a dentry. It returns %NULL if there is insufficient memory |
@@ -1284,7 +1284,7 @@ static struct shrinker dcache_shrinker = { | |||
1284 | * copied and the copy passed in may be reused after this call. | 1284 | * copied and the copy passed in may be reused after this call. |
1285 | */ | 1285 | */ |
1286 | 1286 | ||
1287 | struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | 1287 | struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) |
1288 | { | 1288 | { |
1289 | struct dentry *dentry; | 1289 | struct dentry *dentry; |
1290 | char *dname; | 1290 | char *dname; |
@@ -1314,8 +1314,8 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1314 | spin_lock_init(&dentry->d_lock); | 1314 | spin_lock_init(&dentry->d_lock); |
1315 | seqcount_init(&dentry->d_seq); | 1315 | seqcount_init(&dentry->d_seq); |
1316 | dentry->d_inode = NULL; | 1316 | dentry->d_inode = NULL; |
1317 | dentry->d_parent = NULL; | 1317 | dentry->d_parent = dentry; |
1318 | dentry->d_sb = NULL; | 1318 | dentry->d_sb = sb; |
1319 | dentry->d_op = NULL; | 1319 | dentry->d_op = NULL; |
1320 | dentry->d_fsdata = NULL; | 1320 | dentry->d_fsdata = NULL; |
1321 | INIT_HLIST_BL_NODE(&dentry->d_hash); | 1321 | INIT_HLIST_BL_NODE(&dentry->d_hash); |
@@ -1323,36 +1323,47 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
1323 | INIT_LIST_HEAD(&dentry->d_subdirs); | 1323 | INIT_LIST_HEAD(&dentry->d_subdirs); |
1324 | INIT_LIST_HEAD(&dentry->d_alias); | 1324 | INIT_LIST_HEAD(&dentry->d_alias); |
1325 | INIT_LIST_HEAD(&dentry->d_u.d_child); | 1325 | INIT_LIST_HEAD(&dentry->d_u.d_child); |
1326 | 1326 | d_set_d_op(dentry, dentry->d_sb->s_d_op); | |
1327 | if (parent) { | ||
1328 | spin_lock(&parent->d_lock); | ||
1329 | /* | ||
1330 | * don't need child lock because it is not subject | ||
1331 | * to concurrency here | ||
1332 | */ | ||
1333 | __dget_dlock(parent); | ||
1334 | dentry->d_parent = parent; | ||
1335 | dentry->d_sb = parent->d_sb; | ||
1336 | d_set_d_op(dentry, dentry->d_sb->s_d_op); | ||
1337 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); | ||
1338 | spin_unlock(&parent->d_lock); | ||
1339 | } | ||
1340 | 1327 | ||
1341 | this_cpu_inc(nr_dentry); | 1328 | this_cpu_inc(nr_dentry); |
1342 | 1329 | ||
1343 | return dentry; | 1330 | return dentry; |
1344 | } | 1331 | } |
1332 | |||
1333 | /** | ||
1334 | * d_alloc - allocate a dcache entry | ||
1335 | * @parent: parent of entry to allocate | ||
1336 | * @name: qstr of the name | ||
1337 | * | ||
1338 | * Allocates a dentry. It returns %NULL if there is insufficient memory | ||
1339 | * available. On a success the dentry is returned. The name passed in is | ||
1340 | * copied and the copy passed in may be reused after this call. | ||
1341 | */ | ||
1342 | struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | ||
1343 | { | ||
1344 | struct dentry *dentry = __d_alloc(parent->d_sb, name); | ||
1345 | if (!dentry) | ||
1346 | return NULL; | ||
1347 | |||
1348 | spin_lock(&parent->d_lock); | ||
1349 | /* | ||
1350 | * don't need child lock because it is not subject | ||
1351 | * to concurrency here | ||
1352 | */ | ||
1353 | __dget_dlock(parent); | ||
1354 | dentry->d_parent = parent; | ||
1355 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); | ||
1356 | spin_unlock(&parent->d_lock); | ||
1357 | |||
1358 | return dentry; | ||
1359 | } | ||
1345 | EXPORT_SYMBOL(d_alloc); | 1360 | EXPORT_SYMBOL(d_alloc); |
1346 | 1361 | ||
1347 | struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) | 1362 | struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) |
1348 | { | 1363 | { |
1349 | struct dentry *dentry = d_alloc(NULL, name); | 1364 | struct dentry *dentry = __d_alloc(sb, name); |
1350 | if (dentry) { | 1365 | if (dentry) |
1351 | dentry->d_sb = sb; | ||
1352 | d_set_d_op(dentry, dentry->d_sb->s_d_op); | ||
1353 | dentry->d_parent = dentry; | ||
1354 | dentry->d_flags |= DCACHE_DISCONNECTED; | 1366 | dentry->d_flags |= DCACHE_DISCONNECTED; |
1355 | } | ||
1356 | return dentry; | 1367 | return dentry; |
1357 | } | 1368 | } |
1358 | EXPORT_SYMBOL(d_alloc_pseudo); | 1369 | EXPORT_SYMBOL(d_alloc_pseudo); |
@@ -1522,13 +1533,9 @@ struct dentry * d_alloc_root(struct inode * root_inode) | |||
1522 | if (root_inode) { | 1533 | if (root_inode) { |
1523 | static const struct qstr name = { .name = "/", .len = 1 }; | 1534 | static const struct qstr name = { .name = "/", .len = 1 }; |
1524 | 1535 | ||
1525 | res = d_alloc(NULL, &name); | 1536 | res = __d_alloc(root_inode->i_sb, &name); |
1526 | if (res) { | 1537 | if (res) |
1527 | res->d_sb = root_inode->i_sb; | ||
1528 | d_set_d_op(res, res->d_sb->s_d_op); | ||
1529 | res->d_parent = res; | ||
1530 | d_instantiate(res, root_inode); | 1538 | d_instantiate(res, root_inode); |
1531 | } | ||
1532 | } | 1539 | } |
1533 | return res; | 1540 | return res; |
1534 | } | 1541 | } |
@@ -1589,13 +1596,11 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1589 | if (res) | 1596 | if (res) |
1590 | goto out_iput; | 1597 | goto out_iput; |
1591 | 1598 | ||
1592 | tmp = d_alloc(NULL, &anonstring); | 1599 | tmp = __d_alloc(inode->i_sb, &anonstring); |
1593 | if (!tmp) { | 1600 | if (!tmp) { |
1594 | res = ERR_PTR(-ENOMEM); | 1601 | res = ERR_PTR(-ENOMEM); |
1595 | goto out_iput; | 1602 | goto out_iput; |
1596 | } | 1603 | } |
1597 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ | ||
1598 | |||
1599 | 1604 | ||
1600 | spin_lock(&inode->i_lock); | 1605 | spin_lock(&inode->i_lock); |
1601 | res = __d_find_any_alias(inode); | 1606 | res = __d_find_any_alias(inode); |
@@ -1607,8 +1612,6 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1607 | 1612 | ||
1608 | /* attach a disconnected dentry */ | 1613 | /* attach a disconnected dentry */ |
1609 | spin_lock(&tmp->d_lock); | 1614 | spin_lock(&tmp->d_lock); |
1610 | tmp->d_sb = inode->i_sb; | ||
1611 | d_set_d_op(tmp, tmp->d_sb->s_d_op); | ||
1612 | tmp->d_inode = inode; | 1615 | tmp->d_inode = inode; |
1613 | tmp->d_flags |= DCACHE_DISCONNECTED; | 1616 | tmp->d_flags |= DCACHE_DISCONNECTED; |
1614 | list_add(&tmp->d_alias, &inode->i_dentry); | 1617 | list_add(&tmp->d_alias, &inode->i_dentry); |
diff --git a/fs/internal.h b/fs/internal.h index b29c46e4e32f..ae47c48bedde 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -135,3 +135,8 @@ extern void inode_wb_list_del(struct inode *inode); | |||
135 | extern int get_nr_dirty_inodes(void); | 135 | extern int get_nr_dirty_inodes(void); |
136 | extern void evict_inodes(struct super_block *); | 136 | extern void evict_inodes(struct super_block *); |
137 | extern int invalidate_inodes(struct super_block *, bool); | 137 | extern int invalidate_inodes(struct super_block *, bool); |
138 | |||
139 | /* | ||
140 | * dcache.c | ||
141 | */ | ||
142 | extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); | ||
diff --git a/fs/libfs.c b/fs/libfs.c index 275ca4749a2e..bd50b11f92da 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -16,6 +16,8 @@ | |||
16 | 16 | ||
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | 18 | ||
19 | #include "internal.h" | ||
20 | |||
19 | static inline int simple_positive(struct dentry *dentry) | 21 | static inline int simple_positive(struct dentry *dentry) |
20 | { | 22 | { |
21 | return dentry->d_inode && !d_unhashed(dentry); | 23 | return dentry->d_inode && !d_unhashed(dentry); |
@@ -246,13 +248,11 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, | |||
246 | root->i_ino = 1; | 248 | root->i_ino = 1; |
247 | root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; | 249 | root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; |
248 | root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; | 250 | root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME; |
249 | dentry = d_alloc(NULL, &d_name); | 251 | dentry = __d_alloc(s, &d_name); |
250 | if (!dentry) { | 252 | if (!dentry) { |
251 | iput(root); | 253 | iput(root); |
252 | goto Enomem; | 254 | goto Enomem; |
253 | } | 255 | } |
254 | dentry->d_sb = s; | ||
255 | dentry->d_parent = dentry; | ||
256 | d_instantiate(dentry, root); | 256 | d_instantiate(dentry, root); |
257 | s->s_root = dentry; | 257 | s->s_root = dentry; |
258 | s->s_d_op = dops; | 258 | s->s_d_op = dops; |