Skip to content

Commit 18253e0

Browse files
committed
Merge branch 'work.dcache2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull dcache and mountpoint updates from Al Viro: "Saner handling of refcounts to mountpoints. Transfer the counting reference from struct mount ->mnt_mountpoint over to struct mountpoint ->m_dentry. That allows us to get rid of the convoluted games with ordering of mount shutdowns. The cost is in teaching shrink_dcache_{parent,for_umount} to cope with mixed-filesystem shrink lists, which we'll also need for the Slab Movable Objects patchset" * 'work.dcache2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: switch the remnants of releasing the mountpoint away from fs_pin get rid of detach_mnt() make struct mountpoint bear the dentry reference to mountpoint, not struct mount Teach shrink_dcache_parent() to cope with mixed-filesystem shrink lists fs/namespace.c: shift put_mountpoint() to callers of unhash_mnt() __detach_mounts(): lookup_mountpoint() can't return ERR_PTR() anymore nfs: dget_parent() never returns NULL ceph: don't open-code the check for dead lockref
2 parents abdfd52 + 56cbb42 commit 18253e0

File tree

8 files changed

+172
-116
lines changed

8 files changed

+172
-116
lines changed

fs/ceph/dir.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ __dentry_leases_walk(struct ceph_mds_client *mdsc,
12671267
if (!spin_trylock(&dentry->d_lock))
12681268
continue;
12691269

1270-
if (dentry->d_lockref.count < 0) {
1270+
if (__lockref_is_dead(&dentry->d_lockref)) {
12711271
list_del_init(&di->lease_list);
12721272
goto next;
12731273
}

fs/dcache.c

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,32 @@ void dput(struct dentry *dentry)
861861
}
862862
EXPORT_SYMBOL(dput);
863863

864+
static void __dput_to_list(struct dentry *dentry, struct list_head *list)
865+
__must_hold(&dentry->d_lock)
866+
{
867+
if (dentry->d_flags & DCACHE_SHRINK_LIST) {
868+
/* let the owner of the list it's on deal with it */
869+
--dentry->d_lockref.count;
870+
} else {
871+
if (dentry->d_flags & DCACHE_LRU_LIST)
872+
d_lru_del(dentry);
873+
if (!--dentry->d_lockref.count)
874+
d_shrink_add(dentry, list);
875+
}
876+
}
877+
878+
void dput_to_list(struct dentry *dentry, struct list_head *list)
879+
{
880+
rcu_read_lock();
881+
if (likely(fast_dput(dentry))) {
882+
rcu_read_unlock();
883+
return;
884+
}
885+
rcu_read_unlock();
886+
if (!retain_dentry(dentry))
887+
__dput_to_list(dentry, list);
888+
spin_unlock(&dentry->d_lock);
889+
}
864890

865891
/* This must be called with d_lock held */
866892
static inline void __dget_dlock(struct dentry *dentry)
@@ -1067,7 +1093,7 @@ static bool shrink_lock_dentry(struct dentry *dentry)
10671093
return false;
10681094
}
10691095

1070-
static void shrink_dentry_list(struct list_head *list)
1096+
void shrink_dentry_list(struct list_head *list)
10711097
{
10721098
while (!list_empty(list)) {
10731099
struct dentry *dentry, *parent;
@@ -1089,18 +1115,9 @@ static void shrink_dentry_list(struct list_head *list)
10891115
rcu_read_unlock();
10901116
d_shrink_del(dentry);
10911117
parent = dentry->d_parent;
1118+
if (parent != dentry)
1119+
__dput_to_list(parent, list);
10921120
__dentry_kill(dentry);
1093-
if (parent == dentry)
1094-
continue;
1095-
/*
1096-
* We need to prune ancestors too. This is necessary to prevent
1097-
* quadratic behavior of shrink_dcache_parent(), but is also
1098-
* expected to be beneficial in reducing dentry cache
1099-
* fragmentation.
1100-
*/
1101-
dentry = parent;
1102-
while (dentry && !lockref_put_or_lock(&dentry->d_lockref))
1103-
dentry = dentry_kill(dentry);
11041121
}
11051122
}
11061123

@@ -1445,8 +1462,11 @@ int d_set_mounted(struct dentry *dentry)
14451462

14461463
struct select_data {
14471464
struct dentry *start;
1465+
union {
1466+
long found;
1467+
struct dentry *victim;
1468+
};
14481469
struct list_head dispose;
1449-
int found;
14501470
};
14511471

14521472
static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
@@ -1478,6 +1498,37 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
14781498
return ret;
14791499
}
14801500

1501+
static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry)
1502+
{
1503+
struct select_data *data = _data;
1504+
enum d_walk_ret ret = D_WALK_CONTINUE;
1505+
1506+
if (data->start == dentry)
1507+
goto out;
1508+
1509+
if (dentry->d_flags & DCACHE_SHRINK_LIST) {
1510+
if (!dentry->d_lockref.count) {
1511+
rcu_read_lock();
1512+
data->victim = dentry;
1513+
return D_WALK_QUIT;
1514+
}
1515+
} else {
1516+
if (dentry->d_flags & DCACHE_LRU_LIST)
1517+
d_lru_del(dentry);
1518+
if (!dentry->d_lockref.count)
1519+
d_shrink_add(dentry, &data->dispose);
1520+
}
1521+
/*
1522+
* We can return to the caller if we have found some (this
1523+
* ensures forward progress). We'll be coming back to find
1524+
* the rest.
1525+
*/
1526+
if (!list_empty(&data->dispose))
1527+
ret = need_resched() ? D_WALK_QUIT : D_WALK_NORETRY;
1528+
out:
1529+
return ret;
1530+
}
1531+
14811532
/**
14821533
* shrink_dcache_parent - prune dcache
14831534
* @parent: parent of entries to prune
@@ -1487,12 +1538,9 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
14871538
void shrink_dcache_parent(struct dentry *parent)
14881539
{
14891540
for (;;) {
1490-
struct select_data data;
1541+
struct select_data data = {.start = parent};
14911542

14921543
INIT_LIST_HEAD(&data.dispose);
1493-
data.start = parent;
1494-
data.found = 0;
1495-
14961544
d_walk(parent, &data, select_collect);
14971545

14981546
if (!list_empty(&data.dispose)) {
@@ -1503,6 +1551,24 @@ void shrink_dcache_parent(struct dentry *parent)
15031551
cond_resched();
15041552
if (!data.found)
15051553
break;
1554+
data.victim = NULL;
1555+
d_walk(parent, &data, select_collect2);
1556+
if (data.victim) {
1557+
struct dentry *parent;
1558+
spin_lock(&data.victim->d_lock);
1559+
if (!shrink_lock_dentry(data.victim)) {
1560+
spin_unlock(&data.victim->d_lock);
1561+
rcu_read_unlock();
1562+
} else {
1563+
rcu_read_unlock();
1564+
parent = data.victim->d_parent;
1565+
if (parent != data.victim)
1566+
__dput_to_list(parent, &data.dispose);
1567+
__dentry_kill(data.victim);
1568+
}
1569+
}
1570+
if (!list_empty(&data.dispose))
1571+
shrink_dentry_list(&data.dispose);
15061572
}
15071573
}
15081574
EXPORT_SYMBOL(shrink_dcache_parent);

fs/fs_pin.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,14 @@ void pin_remove(struct fs_pin *pin)
1919
spin_unlock_irq(&pin->wait.lock);
2020
}
2121

22-
void pin_insert_group(struct fs_pin *pin, struct vfsmount *m, struct hlist_head *p)
22+
void pin_insert(struct fs_pin *pin, struct vfsmount *m)
2323
{
2424
spin_lock(&pin_lock);
25-
if (p)
26-
hlist_add_head(&pin->s_list, p);
25+
hlist_add_head(&pin->s_list, &m->mnt_sb->s_pins);
2726
hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins);
2827
spin_unlock(&pin_lock);
2928
}
3029

31-
void pin_insert(struct fs_pin *pin, struct vfsmount *m)
32-
{
33-
pin_insert_group(pin, m, &m->mnt_sb->s_pins);
34-
}
35-
3630
void pin_kill(struct fs_pin *p)
3731
{
3832
wait_queue_entry_t wait;

fs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc);
157157
extern struct dentry *d_alloc_cursor(struct dentry *);
158158
extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
159159
extern char *simple_dname(struct dentry *, char *, int);
160+
extern void dput_to_list(struct dentry *, struct list_head *);
161+
extern void shrink_dentry_list(struct list_head *);
160162

161163
/*
162164
* read_write.c

fs/mount.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ struct mount {
5858
struct mount *mnt_master; /* slave is on master->mnt_slave_list */
5959
struct mnt_namespace *mnt_ns; /* containing namespace */
6060
struct mountpoint *mnt_mp; /* where is it mounted */
61-
struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
61+
union {
62+
struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */
63+
struct hlist_node mnt_umount;
64+
};
6265
struct list_head mnt_umounting; /* list entry for umount propagation */
6366
#ifdef CONFIG_FSNOTIFY
6467
struct fsnotify_mark_connector __rcu *mnt_fsnotify_marks;
@@ -68,8 +71,7 @@ struct mount {
6871
int mnt_group_id; /* peer group identifier */
6972
int mnt_expiry_mark; /* true if marked for expiry */
7073
struct hlist_head mnt_pins;
71-
struct fs_pin mnt_umount;
72-
struct dentry *mnt_ex_mountpoint;
74+
struct hlist_head mnt_stuck_children;
7375
} __randomize_layout;
7476

7577
#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */

0 commit comments

Comments
 (0)