Loading fs/dcache.c +16 −46 Original line number Diff line number Diff line Loading @@ -1542,78 +1542,48 @@ void shrink_dcache_for_umount(struct super_block *sb) } } struct detach_data { struct select_data select; struct dentry *mountpoint; }; static enum d_walk_ret detach_and_collect(void *_data, struct dentry *dentry) static enum d_walk_ret find_submount(void *_data, struct dentry *dentry) { struct detach_data *data = _data; struct dentry **victim = _data; if (d_mountpoint(dentry)) { __dget_dlock(dentry); data->mountpoint = dentry; *victim = dentry; return D_WALK_QUIT; } return select_collect(&data->select, dentry); } static void check_and_drop(void *_data) { struct detach_data *data = _data; if (!data->mountpoint && list_empty(&data->select.dispose)) __d_drop(data->select.start); return D_WALK_CONTINUE; } /** * d_invalidate - detach submounts, prune dcache, and drop * @dentry: dentry to invalidate (aka detach, prune and drop) * * no dcache lock. * * The final d_drop is done as an atomic operation relative to * rename_lock ensuring there are no races with d_set_mounted. This * ensures there are no unhashed dentries on the path to a mountpoint. */ void d_invalidate(struct dentry *dentry) { /* * If it's already been dropped, return OK. */ bool had_submounts = false; spin_lock(&dentry->d_lock); if (d_unhashed(dentry)) { spin_unlock(&dentry->d_lock); return; } __d_drop(dentry); spin_unlock(&dentry->d_lock); /* Negative dentries can be dropped without further checks */ if (!dentry->d_inode) { d_drop(dentry); if (!dentry->d_inode) return; } shrink_dcache_parent(dentry); for (;;) { struct detach_data data; data.mountpoint = NULL; INIT_LIST_HEAD(&data.select.dispose); data.select.start = dentry; data.select.found = 0; d_walk(dentry, &data, detach_and_collect, check_and_drop); if (!list_empty(&data.select.dispose)) shrink_dentry_list(&data.select.dispose); else if (!data.mountpoint) struct dentry *victim = NULL; d_walk(dentry, &victim, find_submount, NULL); if (!victim) { if (had_submounts) shrink_dcache_parent(dentry); return; if (data.mountpoint) { detach_mounts(data.mountpoint); dput(data.mountpoint); } had_submounts = true; detach_mounts(victim); dput(victim); } } EXPORT_SYMBOL(d_invalidate); Loading Loading
fs/dcache.c +16 −46 Original line number Diff line number Diff line Loading @@ -1542,78 +1542,48 @@ void shrink_dcache_for_umount(struct super_block *sb) } } struct detach_data { struct select_data select; struct dentry *mountpoint; }; static enum d_walk_ret detach_and_collect(void *_data, struct dentry *dentry) static enum d_walk_ret find_submount(void *_data, struct dentry *dentry) { struct detach_data *data = _data; struct dentry **victim = _data; if (d_mountpoint(dentry)) { __dget_dlock(dentry); data->mountpoint = dentry; *victim = dentry; return D_WALK_QUIT; } return select_collect(&data->select, dentry); } static void check_and_drop(void *_data) { struct detach_data *data = _data; if (!data->mountpoint && list_empty(&data->select.dispose)) __d_drop(data->select.start); return D_WALK_CONTINUE; } /** * d_invalidate - detach submounts, prune dcache, and drop * @dentry: dentry to invalidate (aka detach, prune and drop) * * no dcache lock. * * The final d_drop is done as an atomic operation relative to * rename_lock ensuring there are no races with d_set_mounted. This * ensures there are no unhashed dentries on the path to a mountpoint. */ void d_invalidate(struct dentry *dentry) { /* * If it's already been dropped, return OK. */ bool had_submounts = false; spin_lock(&dentry->d_lock); if (d_unhashed(dentry)) { spin_unlock(&dentry->d_lock); return; } __d_drop(dentry); spin_unlock(&dentry->d_lock); /* Negative dentries can be dropped without further checks */ if (!dentry->d_inode) { d_drop(dentry); if (!dentry->d_inode) return; } shrink_dcache_parent(dentry); for (;;) { struct detach_data data; data.mountpoint = NULL; INIT_LIST_HEAD(&data.select.dispose); data.select.start = dentry; data.select.found = 0; d_walk(dentry, &data, detach_and_collect, check_and_drop); if (!list_empty(&data.select.dispose)) shrink_dentry_list(&data.select.dispose); else if (!data.mountpoint) struct dentry *victim = NULL; d_walk(dentry, &victim, find_submount, NULL); if (!victim) { if (had_submounts) shrink_dcache_parent(dentry); return; if (data.mountpoint) { detach_mounts(data.mountpoint); dput(data.mountpoint); } had_submounts = true; detach_mounts(victim); dput(victim); } } EXPORT_SYMBOL(d_invalidate); Loading