mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: vfs: new helper - d_make_root() dcache: use a dispose list in select_parent ceph: d_alloc_root() may fail ext4: fix failure exits isofs: inode leak on mount failure
This commit is contained in:
commit
e4e11180df
|
@ -636,19 +636,26 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
|
||||||
req->r_num_caps = 2;
|
req->r_num_caps = 2;
|
||||||
err = ceph_mdsc_do_request(mdsc, NULL, req);
|
err = ceph_mdsc_do_request(mdsc, NULL, req);
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
|
struct inode *inode = req->r_target_inode;
|
||||||
|
req->r_target_inode = NULL;
|
||||||
dout("open_root_inode success\n");
|
dout("open_root_inode success\n");
|
||||||
if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT &&
|
if (ceph_ino(inode) == CEPH_INO_ROOT &&
|
||||||
fsc->sb->s_root == NULL) {
|
fsc->sb->s_root == NULL) {
|
||||||
root = d_alloc_root(req->r_target_inode);
|
root = d_alloc_root(inode);
|
||||||
|
if (!root) {
|
||||||
|
iput(inode);
|
||||||
|
root = ERR_PTR(-ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
ceph_init_dentry(root);
|
ceph_init_dentry(root);
|
||||||
} else {
|
} else {
|
||||||
root = d_obtain_alias(req->r_target_inode);
|
root = d_obtain_alias(inode);
|
||||||
}
|
}
|
||||||
req->r_target_inode = NULL;
|
|
||||||
dout("open_root_inode success, root dentry is %p\n", root);
|
dout("open_root_inode success, root dentry is %p\n", root);
|
||||||
} else {
|
} else {
|
||||||
root = ERR_PTR(err);
|
root = ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
ceph_mdsc_put_request(req);
|
ceph_mdsc_put_request(req);
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
78
fs/dcache.c
78
fs/dcache.c
|
@ -276,15 +276,15 @@ static void dentry_lru_prune(struct dentry *dentry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dentry_lru_move_tail(struct dentry *dentry)
|
static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
|
||||||
{
|
{
|
||||||
spin_lock(&dcache_lru_lock);
|
spin_lock(&dcache_lru_lock);
|
||||||
if (list_empty(&dentry->d_lru)) {
|
if (list_empty(&dentry->d_lru)) {
|
||||||
list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
|
list_add_tail(&dentry->d_lru, list);
|
||||||
dentry->d_sb->s_nr_dentry_unused++;
|
dentry->d_sb->s_nr_dentry_unused++;
|
||||||
dentry_stat.nr_unused++;
|
dentry_stat.nr_unused++;
|
||||||
} else {
|
} else {
|
||||||
list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
|
list_move_tail(&dentry->d_lru, list);
|
||||||
}
|
}
|
||||||
spin_unlock(&dcache_lru_lock);
|
spin_unlock(&dcache_lru_lock);
|
||||||
}
|
}
|
||||||
|
@ -770,14 +770,18 @@ static void shrink_dentry_list(struct list_head *list)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* __shrink_dcache_sb - shrink the dentry LRU on a given superblock
|
* prune_dcache_sb - shrink the dcache
|
||||||
* @sb: superblock to shrink dentry LRU.
|
* @sb: superblock
|
||||||
* @count: number of entries to prune
|
* @count: number of entries to try to free
|
||||||
* @flags: flags to control the dentry processing
|
|
||||||
*
|
*
|
||||||
* If flags contains DCACHE_REFERENCED reference dentries will not be pruned.
|
* Attempt to shrink the superblock dcache LRU by @count entries. This is
|
||||||
|
* done when we need more memory an called from the superblock shrinker
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* This function may fail to free any resources if all the dentries are in
|
||||||
|
* use.
|
||||||
*/
|
*/
|
||||||
static void __shrink_dcache_sb(struct super_block *sb, int count, int flags)
|
void prune_dcache_sb(struct super_block *sb, int count)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
LIST_HEAD(referenced);
|
LIST_HEAD(referenced);
|
||||||
|
@ -796,13 +800,7 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags)
|
||||||
goto relock;
|
goto relock;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (dentry->d_flags & DCACHE_REFERENCED) {
|
||||||
* If we are honouring the DCACHE_REFERENCED flag and the
|
|
||||||
* dentry has this flag set, don't free it. Clear the flag
|
|
||||||
* and put it back on the LRU.
|
|
||||||
*/
|
|
||||||
if (flags & DCACHE_REFERENCED &&
|
|
||||||
dentry->d_flags & DCACHE_REFERENCED) {
|
|
||||||
dentry->d_flags &= ~DCACHE_REFERENCED;
|
dentry->d_flags &= ~DCACHE_REFERENCED;
|
||||||
list_move(&dentry->d_lru, &referenced);
|
list_move(&dentry->d_lru, &referenced);
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
|
@ -821,23 +819,6 @@ static void __shrink_dcache_sb(struct super_block *sb, int count, int flags)
|
||||||
shrink_dentry_list(&tmp);
|
shrink_dentry_list(&tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* prune_dcache_sb - shrink the dcache
|
|
||||||
* @sb: superblock
|
|
||||||
* @nr_to_scan: number of entries to try to free
|
|
||||||
*
|
|
||||||
* Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is
|
|
||||||
* done when we need more memory an called from the superblock shrinker
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* This function may fail to free any resources if all the dentries are in
|
|
||||||
* use.
|
|
||||||
*/
|
|
||||||
void prune_dcache_sb(struct super_block *sb, int nr_to_scan)
|
|
||||||
{
|
|
||||||
__shrink_dcache_sb(sb, nr_to_scan, DCACHE_REFERENCED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shrink_dcache_sb - shrink dcache for a superblock
|
* shrink_dcache_sb - shrink dcache for a superblock
|
||||||
* @sb: superblock
|
* @sb: superblock
|
||||||
|
@ -1092,7 +1073,7 @@ EXPORT_SYMBOL(have_submounts);
|
||||||
* drop the lock and return early due to latency
|
* drop the lock and return early due to latency
|
||||||
* constraints.
|
* constraints.
|
||||||
*/
|
*/
|
||||||
static int select_parent(struct dentry * parent)
|
static int select_parent(struct dentry *parent, struct list_head *dispose)
|
||||||
{
|
{
|
||||||
struct dentry *this_parent;
|
struct dentry *this_parent;
|
||||||
struct list_head *next;
|
struct list_head *next;
|
||||||
|
@ -1115,11 +1096,10 @@ static int select_parent(struct dentry * parent)
|
||||||
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* move only zero ref count dentries to the end
|
* move only zero ref count dentries to the dispose list.
|
||||||
* of the unused list for prune_dcache
|
|
||||||
*/
|
*/
|
||||||
if (!dentry->d_count) {
|
if (!dentry->d_count) {
|
||||||
dentry_lru_move_tail(dentry);
|
dentry_lru_move_list(dentry, dispose);
|
||||||
found++;
|
found++;
|
||||||
} else {
|
} else {
|
||||||
dentry_lru_del(dentry);
|
dentry_lru_del(dentry);
|
||||||
|
@ -1181,14 +1161,13 @@ static int select_parent(struct dentry * parent)
|
||||||
*
|
*
|
||||||
* Prune the dcache to remove unused children of the parent dentry.
|
* Prune the dcache to remove unused children of the parent dentry.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void shrink_dcache_parent(struct dentry * parent)
|
void shrink_dcache_parent(struct dentry * parent)
|
||||||
{
|
{
|
||||||
struct super_block *sb = parent->d_sb;
|
LIST_HEAD(dispose);
|
||||||
int found;
|
int found;
|
||||||
|
|
||||||
while ((found = select_parent(parent)) != 0)
|
while ((found = select_parent(parent, &dispose)) != 0)
|
||||||
__shrink_dcache_sb(sb, found, 0);
|
shrink_dentry_list(&dispose);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(shrink_dcache_parent);
|
EXPORT_SYMBOL(shrink_dcache_parent);
|
||||||
|
|
||||||
|
@ -1461,6 +1440,23 @@ struct dentry * d_alloc_root(struct inode * root_inode)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_alloc_root);
|
EXPORT_SYMBOL(d_alloc_root);
|
||||||
|
|
||||||
|
struct dentry *d_make_root(struct inode *root_inode)
|
||||||
|
{
|
||||||
|
struct dentry *res = NULL;
|
||||||
|
|
||||||
|
if (root_inode) {
|
||||||
|
static const struct qstr name = { .name = "/", .len = 1 };
|
||||||
|
|
||||||
|
res = __d_alloc(root_inode->i_sb, &name);
|
||||||
|
if (res)
|
||||||
|
d_instantiate(res, root_inode);
|
||||||
|
else
|
||||||
|
iput(root_inode);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(d_make_root);
|
||||||
|
|
||||||
static struct dentry * __d_find_any_alias(struct inode *inode)
|
static struct dentry * __d_find_any_alias(struct inode *inode)
|
||||||
{
|
{
|
||||||
struct dentry *alias;
|
struct dentry *alias;
|
||||||
|
|
|
@ -3733,10 +3733,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
}
|
}
|
||||||
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
|
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
|
||||||
ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
|
ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck");
|
||||||
|
iput(root);
|
||||||
goto failed_mount4;
|
goto failed_mount4;
|
||||||
}
|
}
|
||||||
sb->s_root = d_alloc_root(root);
|
sb->s_root = d_alloc_root(root);
|
||||||
if (!sb->s_root) {
|
if (!sb->s_root) {
|
||||||
|
iput(root);
|
||||||
ext4_msg(sb, KERN_ERR, "get root dentry failed");
|
ext4_msg(sb, KERN_ERR, "get root dentry failed");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto failed_mount4;
|
goto failed_mount4;
|
||||||
|
@ -3773,7 +3775,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
if (err) {
|
if (err) {
|
||||||
ext4_msg(sb, KERN_ERR, "failed to initialize system "
|
ext4_msg(sb, KERN_ERR, "failed to initialize system "
|
||||||
"zone (%d)", err);
|
"zone (%d)", err);
|
||||||
goto failed_mount4;
|
goto failed_mount4a;
|
||||||
}
|
}
|
||||||
|
|
||||||
ext4_ext_init(sb);
|
ext4_ext_init(sb);
|
||||||
|
@ -3830,13 +3832,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
failed_mount7:
|
failed_mount7:
|
||||||
ext4_unregister_li_request(sb);
|
ext4_unregister_li_request(sb);
|
||||||
failed_mount6:
|
failed_mount6:
|
||||||
ext4_ext_release(sb);
|
|
||||||
failed_mount5:
|
|
||||||
ext4_mb_release(sb);
|
ext4_mb_release(sb);
|
||||||
|
failed_mount5:
|
||||||
|
ext4_ext_release(sb);
|
||||||
ext4_release_system_zone(sb);
|
ext4_release_system_zone(sb);
|
||||||
failed_mount4:
|
failed_mount4a:
|
||||||
iput(root);
|
dput(sb->s_root);
|
||||||
sb->s_root = NULL;
|
sb->s_root = NULL;
|
||||||
|
failed_mount4:
|
||||||
ext4_msg(sb, KERN_ERR, "mount failed");
|
ext4_msg(sb, KERN_ERR, "mount failed");
|
||||||
destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq);
|
destroy_workqueue(EXT4_SB(sb)->dio_unwritten_wq);
|
||||||
failed_mount_wq:
|
failed_mount_wq:
|
||||||
|
|
|
@ -948,8 +948,11 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
|
||||||
|
|
||||||
/* get the root dentry */
|
/* get the root dentry */
|
||||||
s->s_root = d_alloc_root(inode);
|
s->s_root = d_alloc_root(inode);
|
||||||
if (!(s->s_root))
|
if (!(s->s_root)) {
|
||||||
goto out_no_root;
|
iput(inode);
|
||||||
|
error = -ENOMEM;
|
||||||
|
goto out_no_inode;
|
||||||
|
}
|
||||||
|
|
||||||
kfree(opt.iocharset);
|
kfree(opt.iocharset);
|
||||||
|
|
||||||
|
|
|
@ -249,6 +249,7 @@ extern int d_invalidate(struct dentry *);
|
||||||
|
|
||||||
/* only used at mount-time */
|
/* only used at mount-time */
|
||||||
extern struct dentry * d_alloc_root(struct inode *);
|
extern struct dentry * d_alloc_root(struct inode *);
|
||||||
|
extern struct dentry * d_make_root(struct inode *);
|
||||||
|
|
||||||
/* <clickety>-<click> the ramfs-type tree */
|
/* <clickety>-<click> the ramfs-type tree */
|
||||||
extern void d_genocide(struct dentry *);
|
extern void d_genocide(struct dentry *);
|
||||||
|
|
Loading…
Reference in New Issue