Hi Eric, Today's linux-next merge of the userns tree got a conflict in fs/dcache.c between commit 84550b9356af ("RCU'd vfsmounts") from the vfs tree and commit 40216baa0101 ("vfs: Lazily remove mounts on unlinked files and directories. v2") from the userns tree. I fixed it up (I think - see below) and can carry the fix as necessary (no action is required). Al, I do have to wonder why a commit whose whole commit message is: "RCU'd vfsmounts _very_ preliminary, barely tested." is in linux-next as is not being kept over for v3.14 at this point. -- Cheers, Stephen Rothwell sfr@xxxxxxxxxxxxxxxx diff --cc fs/dcache.c index 6f418c540f76,1e9bf96b0132..000000000000 --- a/fs/dcache.c +++ b/fs/dcache.c @@@ -1362,110 -1478,17 +1362,101 @@@ void shrink_dcache_parent(struct dentr } EXPORT_SYMBOL(shrink_dcache_parent); +static enum d_walk_ret umount_collect(void *_data, struct dentry *dentry) +{ + struct select_data *data = _data; + enum d_walk_ret ret = D_WALK_CONTINUE; + + if (dentry->d_lockref.count) { + dentry_lru_del(dentry); + if (likely(!list_empty(&dentry->d_subdirs))) + goto out; + if (dentry == data->start && dentry->d_lockref.count == 1) + goto out; + printk(KERN_ERR + "BUG: Dentry %p{i=%lx,n=%s}" + " still in use (%d)" + " [unmount of %s %s]\n", + dentry, + dentry->d_inode ? + dentry->d_inode->i_ino : 0UL, + dentry->d_name.name, + dentry->d_lockref.count, + dentry->d_sb->s_type->name, + dentry->d_sb->s_id); + BUG(); + } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { + /* + * We can't use d_lru_shrink_move() because we + * need to get the global LRU lock and do the + * LRU accounting. + */ + d_lru_del(dentry); + d_shrink_add(dentry, &data->dispose); + data->found++; + ret = D_WALK_NORETRY; + } +out: + if (data->found && need_resched()) + ret = D_WALK_QUIT; + return ret; +} + +/* + * destroy the dentries attached to a superblock on unmounting + */ +void shrink_dcache_for_umount(struct super_block *sb) +{ + struct dentry *dentry; + + if (down_read_trylock(&sb->s_umount)) + BUG(); + + dentry = sb->s_root; + sb->s_root = NULL; + for (;;) { + struct select_data data; + + INIT_LIST_HEAD(&data.dispose); + data.start = dentry; + data.found = 0; + + d_walk(dentry, &data, umount_collect, NULL); + if (!data.found) + break; + + shrink_dentry_list(&data.dispose); + cond_resched(); + } + d_drop(dentry); + dput(dentry); + + while (!hlist_bl_empty(&sb->s_anon)) { + struct select_data data; + dentry = hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash); + + INIT_LIST_HEAD(&data.dispose); + data.start = NULL; + data.found = 0; + + d_walk(dentry, &data, umount_collect, NULL); + if (data.found) + shrink_dentry_list(&data.dispose); + cond_resched(); + } +} + - static enum d_walk_ret check_and_collect(void *_data, struct dentry *dentry) + struct detach_data { + struct dentry *found; + }; + static enum d_walk_ret do_detach_submounts(void *ptr, struct dentry *dentry) { - struct select_data *data = _data; + struct detach_data *data = ptr; - if (d_mountpoint(dentry)) { - data->found = -EBUSY; - return D_WALK_QUIT; - } + if (d_mountpoint(dentry)) + data->found = dentry; - return select_collect(_data, dentry); - } - - static void check_and_drop(void *_data) - { - struct select_data *data = _data; - - if (d_mountpoint(data->start)) - data->found = -EBUSY; - if (!data->found) - __d_drop(data->start); + return data->found ? D_WALK_QUIT : D_WALK_CONTINUE; } /**
Attachment:
pgpGS4ZkOmFDH.pgp
Description: PGP signature