Merge tag 'pull-persistency' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull persistent dentry infrastructure and conversion from Al Viro:
 "Some filesystems use a kinda-sorta controlled dentry refcount leak to
  pin dentries of created objects in dcache (and undo it when removing
  those). A reference is grabbed and not released, but it's not actually
  _stored_ anywhere.

  That works, but it's hard to follow and verify; among other things, we
  have no way to tell _which_ of the increments is intended to be an
  unpaired one. Worse, on removal we need to decide whether the
  reference had already been dropped, which can be non-trivial if that
  removal is on umount and we need to figure out if this dentry is
  pinned due to e.g. unlink() not done. Usually that is handled by using
  kill_litter_super() as ->kill_sb(), but there are open-coded special
  cases of the same (consider e.g. /proc/self).

  Things get simpler if we introduce a new dentry flag
  (DCACHE_PERSISTENT) marking those "leaked" dentries. Having it set
  claims responsibility for +1 in refcount.

  The end result this series is aiming for:

   - get these unbalanced dget() and dput() replaced with new primitives
     that would, in addition to adjusting refcount, set and clear
     persistency flag.

   - instead of having kill_litter_super() mess with removing the
     remaining "leaked" references (e.g. for all tmpfs files that hadn't
     been removed prior to umount), have the regular
     shrink_dcache_for_umount() strip DCACHE_PERSISTENT of all dentries,
     dropping the corresponding reference if it had been set. After that
     kill_litter_super() becomes an equivalent of kill_anon_super().

  Doing that in a single step is not feasible - it would affect too many
  places in too many filesystems. It has to be split into a series.

  This work has really started early in 2024; quite a few preliminary
  pieces have already gone into mainline. This chunk is finally getting
  to the meat of that stuff - infrastructure and most of the conversions
  to it.

  Some pieces are still sitting in the local branches, but the bulk of
  that stuff is here"

* tag 'pull-persistency' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (54 commits)
  d_make_discardable(): warn if given a non-persistent dentry
  kill securityfs_recursive_remove()
  convert securityfs
  get rid of kill_litter_super()
  convert rust_binderfs
  convert nfsctl
  convert rpc_pipefs
  convert hypfs
  hypfs: swich hypfs_create_u64() to returning int
  hypfs: switch hypfs_create_str() to returning int
  hypfs: don't pin dentries twice
  convert gadgetfs
  gadgetfs: switch to simple_remove_by_name()
  convert functionfs
  functionfs: switch to simple_remove_by_name()
  functionfs: fix the open/removal races
  functionfs: need to cancel ->reset_work in ->kill_sb()
  functionfs: don't bother with ffs->ref in ffs_data_{opened,closed}()
  functionfs: don't abuse ffs_data_closed() on fs shutdown
  convert selinuxfs
  ...
This commit is contained in:
Linus Torvalds
2025-12-05 14:36:21 -08:00
53 changed files with 648 additions and 833 deletions
+7
View File
@@ -1327,3 +1327,10 @@ When vfs_mkdir() returns an error, and so both dputs() the original
dentry and doesn't provide a replacement, it also unlocks the parent.
Consequently the return value from vfs_mkdir() can be passed to
end_creating() and the parent will be unlocked precisely when necessary.
---
**mandatory**
kill_litter_super() is gone; convert to DCACHE_PERSISTENT use (as all
in-tree filesystems have done).
+7 -10
View File
@@ -127,7 +127,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry,
inode->i_fop = fops;
inode->i_size = size;
inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
d_add(dentry, inode);
d_make_persistent(dentry, inode);
out:
return ret;
}
@@ -163,10 +163,9 @@ static int spufs_fill_dir(struct dentry *dir,
return -ENOMEM;
ret = spufs_new_file(dir->d_sb, dentry, files->ops,
files->mode & mode, files->size, ctx);
if (ret) {
dput(dentry);
dput(dentry);
if (ret)
return ret;
}
files++;
}
return 0;
@@ -241,11 +240,10 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
inode_lock(inode);
dget(dentry);
inc_nlink(dir);
inc_nlink(inode);
d_instantiate(dentry, inode);
d_make_persistent(dentry, inode);
if (flags & SPU_CREATE_NOSCHED)
ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
@@ -468,10 +466,9 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, umode_t mode)
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
d_instantiate(dentry, inode);
dget(dentry);
inc_nlink(dir);
inc_nlink(d_inode(dentry));
inc_nlink(inode);
d_make_persistent(dentry, inode);
return ret;
out_iput:
@@ -758,7 +755,7 @@ static struct file_system_type spufs_type = {
.name = "spufs",
.init_fs_context = spufs_init_fs_context,
.parameters = spufs_fs_parameters,
.kill_sb = kill_litter_super,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("spufs");
+2 -4
View File
@@ -22,11 +22,9 @@
extern struct dentry *hypfs_mkdir(struct dentry *parent, const char *name);
extern struct dentry *hypfs_create_u64(struct dentry *dir, const char *name,
__u64 value);
extern int hypfs_create_u64(struct dentry *dir, const char *name, __u64 value);
extern struct dentry *hypfs_create_str(struct dentry *dir, const char *name,
char *string);
extern int hypfs_create_str(struct dentry *dir, const char *name, char *string);
/* LPAR Hypervisor */
extern int hypfs_diag_init(void);
+21 -39
View File
@@ -203,7 +203,7 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
{
struct dentry *cpu_dir;
char buffer[TMP_SIZE];
void *rc;
int rc;
snprintf(buffer, TMP_SIZE, "%d", cpu_info__cpu_addr(diag204_get_info_type(),
cpu_info));
@@ -213,22 +213,21 @@ static int hypfs_create_cpu_files(struct dentry *cpus_dir, void *cpu_info)
rc = hypfs_create_u64(cpu_dir, "mgmtime",
cpu_info__acc_time(diag204_get_info_type(), cpu_info) -
cpu_info__lp_time(diag204_get_info_type(), cpu_info));
if (IS_ERR(rc))
return PTR_ERR(rc);
if (rc)
return rc;
rc = hypfs_create_u64(cpu_dir, "cputime",
cpu_info__lp_time(diag204_get_info_type(), cpu_info));
if (IS_ERR(rc))
return PTR_ERR(rc);
if (rc)
return rc;
if (diag204_get_info_type() == DIAG204_INFO_EXT) {
rc = hypfs_create_u64(cpu_dir, "onlinetime",
cpu_info__online_time(diag204_get_info_type(),
cpu_info));
if (IS_ERR(rc))
return PTR_ERR(rc);
if (rc)
return rc;
}
diag224_idx2name(cpu_info__ctidx(diag204_get_info_type(), cpu_info), buffer);
rc = hypfs_create_str(cpu_dir, "type", buffer);
return PTR_ERR_OR_ZERO(rc);
return hypfs_create_str(cpu_dir, "type", buffer);
}
static void *hypfs_create_lpar_files(struct dentry *systems_dir, void *part_hdr)
@@ -263,7 +262,7 @@ static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
{
struct dentry *cpu_dir;
char buffer[TMP_SIZE];
void *rc;
int rc;
snprintf(buffer, TMP_SIZE, "%i", phys_cpu__cpu_addr(diag204_get_info_type(),
cpu_info));
@@ -272,11 +271,10 @@ static int hypfs_create_phys_cpu_files(struct dentry *cpus_dir, void *cpu_info)
return PTR_ERR(cpu_dir);
rc = hypfs_create_u64(cpu_dir, "mgmtime",
phys_cpu__mgm_time(diag204_get_info_type(), cpu_info));
if (IS_ERR(rc))
return PTR_ERR(rc);
if (rc)
return rc;
diag224_idx2name(phys_cpu__ctidx(diag204_get_info_type(), cpu_info), buffer);
rc = hypfs_create_str(cpu_dir, "type", buffer);
return PTR_ERR_OR_ZERO(rc);
return hypfs_create_str(cpu_dir, "type", buffer);
}
static void *hypfs_create_phys_files(struct dentry *parent_dir, void *phys_hdr)
@@ -315,41 +313,25 @@ int hypfs_diag_create_files(struct dentry *root)
return rc;
systems_dir = hypfs_mkdir(root, "systems");
if (IS_ERR(systems_dir)) {
rc = PTR_ERR(systems_dir);
goto err_out;
}
if (IS_ERR(systems_dir))
return PTR_ERR(systems_dir);
time_hdr = (struct x_info_blk_hdr *)buffer;
part_hdr = time_hdr + info_blk_hdr__size(diag204_get_info_type());
for (i = 0; i < info_blk_hdr__npar(diag204_get_info_type(), time_hdr); i++) {
part_hdr = hypfs_create_lpar_files(systems_dir, part_hdr);
if (IS_ERR(part_hdr)) {
rc = PTR_ERR(part_hdr);
goto err_out;
}
if (IS_ERR(part_hdr))
return PTR_ERR(part_hdr);
}
if (info_blk_hdr__flags(diag204_get_info_type(), time_hdr) &
DIAG204_LPAR_PHYS_FLG) {
ptr = hypfs_create_phys_files(root, part_hdr);
if (IS_ERR(ptr)) {
rc = PTR_ERR(ptr);
goto err_out;
}
if (IS_ERR(ptr))
return PTR_ERR(ptr);
}
hyp_dir = hypfs_mkdir(root, "hyp");
if (IS_ERR(hyp_dir)) {
rc = PTR_ERR(hyp_dir);
goto err_out;
}
ptr = hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
if (IS_ERR(ptr)) {
rc = PTR_ERR(ptr);
goto err_out;
}
rc = 0;
err_out:
return rc;
if (IS_ERR(hyp_dir))
return PTR_ERR(hyp_dir);
return hypfs_create_str(hyp_dir, "type", "LPAR Hypervisor");
}
/* Diagnose 224 functions */
+8 -13
View File
@@ -19,10 +19,9 @@
#define ATTRIBUTE(dir, name, member) \
do { \
void *rc; \
rc = hypfs_create_u64(dir, name, member); \
if (IS_ERR(rc)) \
return PTR_ERR(rc); \
int rc = hypfs_create_u64(dir, name, member); \
if (rc) \
return rc; \
} while (0)
static int hypfs_vm_create_guest(struct dentry *systems_dir,
@@ -85,7 +84,7 @@ static int hypfs_vm_create_guest(struct dentry *systems_dir,
int hypfs_vm_create_files(struct dentry *root)
{
struct dentry *dir, *file;
struct dentry *dir;
struct diag2fc_data *data;
unsigned int count = 0;
int rc, i;
@@ -100,11 +99,9 @@ int hypfs_vm_create_files(struct dentry *root)
rc = PTR_ERR(dir);
goto failed;
}
file = hypfs_create_str(dir, "type", "z/VM Hypervisor");
if (IS_ERR(file)) {
rc = PTR_ERR(file);
rc = hypfs_create_str(dir, "type", "z/VM Hypervisor");
if (rc)
goto failed;
}
/* physical cpus */
dir = hypfs_mkdir(root, "cpus");
@@ -112,11 +109,9 @@ int hypfs_vm_create_files(struct dentry *root)
rc = PTR_ERR(dir);
goto failed;
}
file = hypfs_create_u64(dir, "count", data->lcpus);
if (IS_ERR(file)) {
rc = PTR_ERR(file);
rc = hypfs_create_u64(dir, "count", data->lcpus);
if (rc)
goto failed;
}
/* guests */
dir = hypfs_mkdir(root, "systems");
+27 -55
View File
@@ -60,33 +60,17 @@ static void hypfs_update_update(struct super_block *sb)
static void hypfs_add_dentry(struct dentry *dentry)
{
dentry->d_fsdata = hypfs_last_dentry;
hypfs_last_dentry = dentry;
}
static void hypfs_remove(struct dentry *dentry)
{
struct dentry *parent;
parent = dentry->d_parent;
inode_lock(d_inode(parent));
if (simple_positive(dentry)) {
if (d_is_dir(dentry))
simple_rmdir(d_inode(parent), dentry);
else
simple_unlink(d_inode(parent), dentry);
if (IS_ROOT(dentry->d_parent)) {
dentry->d_fsdata = hypfs_last_dentry;
hypfs_last_dentry = dentry;
}
d_drop(dentry);
dput(dentry);
inode_unlock(d_inode(parent));
}
static void hypfs_delete_tree(struct dentry *root)
static void hypfs_delete_tree(void)
{
while (hypfs_last_dentry) {
struct dentry *next_dentry;
next_dentry = hypfs_last_dentry->d_fsdata;
hypfs_remove(hypfs_last_dentry);
struct dentry *next_dentry = hypfs_last_dentry->d_fsdata;
simple_recursive_removal(hypfs_last_dentry, NULL);
hypfs_last_dentry = next_dentry;
}
}
@@ -183,14 +167,14 @@ static ssize_t hypfs_write_iter(struct kiocb *iocb, struct iov_iter *from)
rc = -EBUSY;
goto out;
}
hypfs_delete_tree(sb->s_root);
hypfs_delete_tree();
if (machine_is_vm())
rc = hypfs_vm_create_files(sb->s_root);
else
rc = hypfs_diag_create_files(sb->s_root);
if (rc) {
pr_err("Updating the hypfs tree failed\n");
hypfs_delete_tree(sb->s_root);
hypfs_delete_tree();
goto out;
}
hypfs_update_update(sb);
@@ -325,13 +309,9 @@ static void hypfs_kill_super(struct super_block *sb)
{
struct hypfs_sb_info *sb_info = sb->s_fs_info;
if (sb->s_root)
hypfs_delete_tree(sb->s_root);
if (sb_info && sb_info->update_file)
hypfs_remove(sb_info->update_file);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
kill_litter_super(sb);
hypfs_last_dentry = NULL;
kill_anon_super(sb);
kfree(sb_info);
}
static struct dentry *hypfs_create_file(struct dentry *parent, const char *name,
@@ -340,17 +320,13 @@ static struct dentry *hypfs_create_file(struct dentry *parent, const char *name,
struct dentry *dentry;
struct inode *inode;
inode_lock(d_inode(parent));
dentry = lookup_noperm(&QSTR(name), parent);
if (IS_ERR(dentry)) {
dentry = ERR_PTR(-ENOMEM);
goto fail;
}
dentry = simple_start_creating(parent, name);
if (IS_ERR(dentry))
return ERR_PTR(-ENOMEM);
inode = hypfs_make_inode(parent->d_sb, mode);
if (!inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto fail;
simple_done_creating(dentry);
return ERR_PTR(-ENOMEM);
}
if (S_ISREG(mode)) {
inode->i_fop = &hypfs_file_ops;
@@ -365,11 +341,9 @@ static struct dentry *hypfs_create_file(struct dentry *parent, const char *name,
} else
BUG();
inode->i_private = data;
d_instantiate(dentry, inode);
dget(dentry);
fail:
inode_unlock(d_inode(parent));
return dentry;
d_make_persistent(dentry, inode);
simple_done_creating(dentry);
return dentry; // borrowed
}
struct dentry *hypfs_mkdir(struct dentry *parent, const char *name)
@@ -397,8 +371,7 @@ static struct dentry *hypfs_create_update_file(struct dentry *dir)
return dentry;
}
struct dentry *hypfs_create_u64(struct dentry *dir,
const char *name, __u64 value)
int hypfs_create_u64(struct dentry *dir, const char *name, __u64 value)
{
char *buffer;
char tmp[TMP_SIZE];
@@ -407,35 +380,34 @@ struct dentry *hypfs_create_u64(struct dentry *dir,
snprintf(tmp, TMP_SIZE, "%llu\n", (unsigned long long int)value);
buffer = kstrdup(tmp, GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
return -ENOMEM;
dentry =
hypfs_create_file(dir, name, buffer, S_IFREG | REG_FILE_MODE);
if (IS_ERR(dentry)) {
kfree(buffer);
return ERR_PTR(-ENOMEM);
return -ENOMEM;
}
hypfs_add_dentry(dentry);
return dentry;
return 0;
}
struct dentry *hypfs_create_str(struct dentry *dir,
const char *name, char *string)
int hypfs_create_str(struct dentry *dir, const char *name, char *string)
{
char *buffer;
struct dentry *dentry;
buffer = kmalloc(strlen(string) + 2, GFP_KERNEL);
if (!buffer)
return ERR_PTR(-ENOMEM);
return -ENOMEM;
sprintf(buffer, "%s\n", string);
dentry =
hypfs_create_file(dir, name, buffer, S_IFREG | REG_FILE_MODE);
if (IS_ERR(dentry)) {
kfree(buffer);
return ERR_PTR(-ENOMEM);
return -ENOMEM;
}
hypfs_add_dentry(dentry);
return dentry;
return 0;
}
static const struct file_operations hypfs_file_ops = {
+33 -88
View File
@@ -178,28 +178,17 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
}
root = sb->s_root;
inode_lock(d_inode(root));
/* look it up */
dentry = lookup_noperm(&QSTR(req->name), root);
dentry = simple_start_creating(root, req->name);
if (IS_ERR(dentry)) {
inode_unlock(d_inode(root));
ret = PTR_ERR(dentry);
goto err;
}
if (d_really_is_positive(dentry)) {
/* already exists */
dput(dentry);
inode_unlock(d_inode(root));
ret = -EEXIST;
goto err;
}
inode->i_private = device;
d_instantiate(dentry, inode);
d_make_persistent(dentry, inode);
fsnotify_create(root->d_inode, dentry);
inode_unlock(d_inode(root));
simple_done_creating(dentry);
return 0;
@@ -472,37 +461,9 @@ static struct inode *binderfs_make_inode(struct super_block *sb, int mode)
return ret;
}
static struct dentry *binderfs_create_dentry(struct dentry *parent,
const char *name)
{
struct dentry *dentry;
dentry = lookup_noperm(&QSTR(name), parent);
if (IS_ERR(dentry))
return dentry;
/* Return error if the file/dir already exists. */
if (d_really_is_positive(dentry)) {
dput(dentry);
return ERR_PTR(-EEXIST);
}
return dentry;
}
void rust_binderfs_remove_file(struct dentry *dentry)
{
struct inode *parent_inode;
parent_inode = d_inode(dentry->d_parent);
inode_lock(parent_inode);
if (simple_positive(dentry)) {
dget(dentry);
simple_unlink(parent_inode, dentry);
d_delete(dentry);
dput(dentry);
}
inode_unlock(parent_inode);
simple_recursive_removal(dentry, NULL);
}
static struct dentry *rust_binderfs_create_file(struct dentry *parent, const char *name,
@@ -510,31 +471,23 @@ static struct dentry *rust_binderfs_create_file(struct dentry *parent, const cha
void *data)
{
struct dentry *dentry;
struct inode *new_inode, *parent_inode;
struct super_block *sb;
parent_inode = d_inode(parent);
inode_lock(parent_inode);
dentry = binderfs_create_dentry(parent, name);
if (IS_ERR(dentry))
goto out;
sb = parent_inode->i_sb;
new_inode = binderfs_make_inode(sb, S_IFREG | 0444);
if (!new_inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto out;
}
struct inode *new_inode;
new_inode = binderfs_make_inode(parent->d_sb, S_IFREG | 0444);
if (!new_inode)
return ERR_PTR(-ENOMEM);
new_inode->i_fop = fops;
new_inode->i_private = data;
d_instantiate(dentry, new_inode);
fsnotify_create(parent_inode, dentry);
out:
inode_unlock(parent_inode);
dentry = simple_start_creating(parent, name);
if (IS_ERR(dentry)) {
iput(new_inode);
return dentry;
}
d_make_persistent(dentry, new_inode);
fsnotify_create(parent->d_inode, dentry);
simple_done_creating(dentry);
return dentry;
}
@@ -556,34 +509,26 @@ static struct dentry *binderfs_create_dir(struct dentry *parent,
const char *name)
{
struct dentry *dentry;
struct inode *new_inode, *parent_inode;
struct super_block *sb;
struct inode *new_inode;
parent_inode = d_inode(parent);
inode_lock(parent_inode);
dentry = binderfs_create_dentry(parent, name);
if (IS_ERR(dentry))
goto out;
sb = parent_inode->i_sb;
new_inode = binderfs_make_inode(sb, S_IFDIR | 0755);
if (!new_inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto out;
}
new_inode = binderfs_make_inode(parent->d_sb, S_IFDIR | 0755);
if (!new_inode)
return ERR_PTR(-ENOMEM);
new_inode->i_fop = &simple_dir_operations;
new_inode->i_op = &simple_dir_inode_operations;
set_nlink(new_inode, 2);
d_instantiate(dentry, new_inode);
inc_nlink(parent_inode);
fsnotify_mkdir(parent_inode, dentry);
dentry = simple_start_creating(parent, name);
if (IS_ERR(dentry)) {
iput(new_inode);
return dentry;
}
out:
inode_unlock(parent_inode);
inc_nlink(parent->d_inode);
set_nlink(new_inode, 2);
d_make_persistent(dentry, new_inode);
fsnotify_mkdir(parent->d_inode, dentry);
simple_done_creating(dentry);
return dentry;
}
@@ -802,7 +747,7 @@ static void binderfs_kill_super(struct super_block *sb)
* During inode eviction struct binderfs_info is needed.
* So first wipe the super_block then free struct binderfs_info.
*/
kill_litter_super(sb);
kill_anon_super(sb);
if (info && info->ipc_ns)
put_ipc_ns(info->ipc_ns);
+19 -63
View File
@@ -183,28 +183,15 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
}
root = sb->s_root;
inode_lock(d_inode(root));
/* look it up */
dentry = lookup_noperm(&QSTR(name), root);
dentry = simple_start_creating(root, name);
if (IS_ERR(dentry)) {
inode_unlock(d_inode(root));
ret = PTR_ERR(dentry);
goto err;
}
if (d_really_is_positive(dentry)) {
/* already exists */
dput(dentry);
inode_unlock(d_inode(root));
ret = -EEXIST;
goto err;
}
inode->i_private = device;
d_instantiate(dentry, inode);
d_make_persistent(dentry, inode);
fsnotify_create(root->d_inode, dentry);
inode_unlock(d_inode(root));
simple_done_creating(dentry);
binder_add_device(device);
@@ -410,12 +397,6 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
if (!device)
return -ENOMEM;
/* If we have already created a binder-control node, return. */
if (info->control_dentry) {
ret = 0;
goto out;
}
ret = -ENOMEM;
inode = new_inode(sb);
if (!inode)
@@ -451,7 +432,8 @@ static int binderfs_binder_ctl_create(struct super_block *sb)
inode->i_private = device;
info->control_dentry = dentry;
d_add(dentry, inode);
d_make_persistent(dentry, inode);
dput(dentry);
return 0;
@@ -481,24 +463,6 @@ static struct inode *binderfs_make_inode(struct super_block *sb, int mode)
return ret;
}
static struct dentry *binderfs_create_dentry(struct dentry *parent,
const char *name)
{
struct dentry *dentry;
dentry = lookup_noperm(&QSTR(name), parent);
if (IS_ERR(dentry))
return dentry;
/* Return error if the file/dir already exists. */
if (d_really_is_positive(dentry)) {
dput(dentry);
return ERR_PTR(-EEXIST);
}
return dentry;
}
struct dentry *binderfs_create_file(struct dentry *parent, const char *name,
const struct file_operations *fops,
void *data)
@@ -508,28 +472,24 @@ struct dentry *binderfs_create_file(struct dentry *parent, const char *name,
struct super_block *sb;
parent_inode = d_inode(parent);
inode_lock(parent_inode);
dentry = binderfs_create_dentry(parent, name);
dentry = simple_start_creating(parent, name);
if (IS_ERR(dentry))
goto out;
return dentry;
sb = parent_inode->i_sb;
new_inode = binderfs_make_inode(sb, S_IFREG | 0444);
if (!new_inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto out;
simple_done_creating(dentry);
return ERR_PTR(-ENOMEM);
}
new_inode->i_fop = fops;
new_inode->i_private = data;
d_instantiate(dentry, new_inode);
d_make_persistent(dentry, new_inode);
fsnotify_create(parent_inode, dentry);
out:
inode_unlock(parent_inode);
return dentry;
simple_done_creating(dentry);
return dentry; // borrowed
}
static struct dentry *binderfs_create_dir(struct dentry *parent,
@@ -540,30 +500,26 @@ static struct dentry *binderfs_create_dir(struct dentry *parent,
struct super_block *sb;
parent_inode = d_inode(parent);
inode_lock(parent_inode);
dentry = binderfs_create_dentry(parent, name);
dentry = simple_start_creating(parent, name);
if (IS_ERR(dentry))
goto out;
return dentry;
sb = parent_inode->i_sb;
new_inode = binderfs_make_inode(sb, S_IFDIR | 0755);
if (!new_inode) {
dput(dentry);
dentry = ERR_PTR(-ENOMEM);
goto out;
simple_done_creating(dentry);
return ERR_PTR(-ENOMEM);
}
new_inode->i_fop = &simple_dir_operations;
new_inode->i_op = &simple_dir_inode_operations;
set_nlink(new_inode, 2);
d_instantiate(dentry, new_inode);
d_make_persistent(dentry, new_inode);
inc_nlink(parent_inode);
fsnotify_mkdir(parent_inode, dentry);
out:
inode_unlock(parent_inode);
simple_done_creating(dentry);
return dentry;
}
@@ -779,7 +735,7 @@ static void binderfs_kill_super(struct super_block *sb)
* During inode eviction struct binderfs_info is needed.
* So first wipe the super_block then free struct binderfs_info.
*/
kill_litter_super(sb);
kill_anon_super(sb);
if (info && info->ipc_ns)
put_ipc_ns(info->ipc_ns);
+1 -1
View File
@@ -70,7 +70,7 @@ static struct file_system_type internal_fs_type = {
#else
.init_fs_context = ramfs_init_fs_context,
#endif
.kill_sb = kill_litter_super,
.kill_sb = kill_anon_super,
};
/* Simply take a ref on the existing mount */
+12 -12
View File
@@ -97,13 +97,11 @@ static const struct super_operations ibmasmfs_s_ops = {
.drop_inode = inode_just_drop,
};
static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations;
static struct file_system_type ibmasmfs_type = {
.owner = THIS_MODULE,
.name = "ibmasmfs",
.init_fs_context = ibmasmfs_init_fs_context,
.kill_sb = kill_litter_super,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("ibmasmfs");
@@ -122,7 +120,7 @@ static int ibmasmfs_fill_super(struct super_block *sb, struct fs_context *fc)
return -ENOMEM;
root->i_op = &simple_dir_inode_operations;
root->i_fop = ibmasmfs_dir_ops;
root->i_fop = &simple_dir_operations;
sb->s_root = d_make_root(root);
if (!sb->s_root)
@@ -144,7 +142,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
return ret;
}
static struct dentry *ibmasmfs_create_file(struct dentry *parent,
static int ibmasmfs_create_file(struct dentry *parent,
const char *name,
const struct file_operations *fops,
void *data,
@@ -155,19 +153,20 @@ static struct dentry *ibmasmfs_create_file(struct dentry *parent,
dentry = d_alloc_name(parent, name);
if (!dentry)
return NULL;
return -ENOMEM;
inode = ibmasmfs_make_inode(parent->d_sb, S_IFREG | mode);
if (!inode) {
dput(dentry);
return NULL;
return -ENOMEM;
}
inode->i_fop = fops;
inode->i_private = data;
d_add(dentry, inode);
return dentry;
d_make_persistent(dentry, inode);
dput(dentry);
return 0;
}
static struct dentry *ibmasmfs_create_dir(struct dentry *parent,
@@ -187,10 +186,11 @@ static struct dentry *ibmasmfs_create_dir(struct dentry *parent,
}
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = ibmasmfs_dir_ops;
inode->i_fop = &simple_dir_operations;
d_add(dentry, inode);
return dentry;
d_make_persistent(dentry, inode);
dput(dentry);
return dentry; // borrowed
}
int ibmasmfs_register(void)
+86 -58
View File
@@ -160,8 +160,6 @@ struct ffs_epfile {
struct ffs_data *ffs;
struct ffs_ep *ep; /* P: ffs->eps_lock */
struct dentry *dentry;
/*
* Buffer for holding data from partial reads which may happen since
* were rounding user read requests to a multiple of a max packet size.
@@ -271,11 +269,11 @@ struct ffs_desc_helper {
};
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
static void ffs_epfiles_destroy(struct super_block *sb,
struct ffs_epfile *epfiles, unsigned count);
static struct dentry *
ffs_sb_create_file(struct super_block *sb, const char *name, void *data,
const struct file_operations *fops);
static int ffs_sb_create_file(struct super_block *sb, const char *name,
void *data, const struct file_operations *fops);
/* Devices management *******************************************************/
@@ -640,13 +638,22 @@ done_mutex:
static int ffs_ep0_open(struct inode *inode, struct file *file)
{
struct ffs_data *ffs = inode->i_private;
struct ffs_data *ffs = inode->i_sb->s_fs_info;
int ret;
if (ffs->state == FFS_CLOSING)
return -EBUSY;
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
if (ret < 0)
return ret;
file->private_data = ffs;
ffs_data_opened(ffs);
if (ffs->state == FFS_CLOSING) {
ffs_data_closed(ffs);
mutex_unlock(&ffs->mutex);
return -EBUSY;
}
mutex_unlock(&ffs->mutex);
file->private_data = ffs;
return stream_open(inode, file);
}
@@ -1193,14 +1200,33 @@ error:
static int
ffs_epfile_open(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
struct ffs_data *ffs = inode->i_sb->s_fs_info;
struct ffs_epfile *epfile;
int ret;
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
/* Acquire mutex */
ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK);
if (ret < 0)
return ret;
if (!atomic_inc_not_zero(&ffs->opened)) {
mutex_unlock(&ffs->mutex);
return -ENODEV;
}
/*
* we want the state to be FFS_ACTIVE; FFS_ACTIVE alone is
* not enough, though - we might have been through FFS_CLOSING
* and back to FFS_ACTIVE, with our file already removed.
*/
epfile = smp_load_acquire(&inode->i_private);
if (unlikely(ffs->state != FFS_ACTIVE || !epfile)) {
mutex_unlock(&ffs->mutex);
ffs_data_closed(ffs);
return -ENODEV;
}
mutex_unlock(&ffs->mutex);
file->private_data = epfile;
ffs_data_opened(epfile->ffs);
return stream_open(inode, file);
}
@@ -1332,7 +1358,7 @@ static void ffs_dmabuf_put(struct dma_buf_attachment *attach)
static int
ffs_epfile_release(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
struct ffs_epfile *epfile = file->private_data;
struct ffs_dmabuf_priv *priv, *tmp;
struct ffs_data *ffs = epfile->ffs;
@@ -1866,26 +1892,26 @@ ffs_sb_make_inode(struct super_block *sb, void *data,
}
/* Create "regular" file */
static struct dentry *ffs_sb_create_file(struct super_block *sb,
const char *name, void *data,
const struct file_operations *fops)
static int ffs_sb_create_file(struct super_block *sb, const char *name,
void *data, const struct file_operations *fops)
{
struct ffs_data *ffs = sb->s_fs_info;
struct dentry *dentry;
struct inode *inode;
dentry = d_alloc_name(sb->s_root, name);
if (!dentry)
return NULL;
inode = ffs_sb_make_inode(sb, data, fops, NULL, &ffs->file_perms);
if (!inode) {
dput(dentry);
return NULL;
if (!inode)
return -ENOMEM;
dentry = simple_start_creating(sb->s_root, name);
if (IS_ERR(dentry)) {
iput(inode);
return PTR_ERR(dentry);
}
d_add(dentry, inode);
return dentry;
d_make_persistent(dentry, inode);
simple_done_creating(dentry);
return 0;
}
/* Super block */
@@ -1928,10 +1954,7 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
return -ENOMEM;
/* EP0 file */
if (!ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations))
return -ENOMEM;
return 0;
return ffs_sb_create_file(sb, "ep0", ffs, &ffs_ep0_operations);
}
enum {
@@ -2071,12 +2094,21 @@ static int ffs_fs_init_fs_context(struct fs_context *fc)
return 0;
}
static void ffs_data_reset(struct ffs_data *ffs);
static void
ffs_fs_kill_sb(struct super_block *sb)
{
kill_litter_super(sb);
if (sb->s_fs_info)
ffs_data_closed(sb->s_fs_info);
kill_anon_super(sb);
if (sb->s_fs_info) {
struct ffs_data *ffs = sb->s_fs_info;
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
// no configfs accesses from that point on,
// so no further schedule_work() is possible
cancel_work_sync(&ffs->reset_work);
ffs_data_put(ffs);
}
}
static struct file_system_type ffs_fs_type = {
@@ -2114,7 +2146,6 @@ static void functionfs_cleanup(void)
/* ffs_data and ffs_function construction and destruction code **************/
static void ffs_data_clear(struct ffs_data *ffs);
static void ffs_data_reset(struct ffs_data *ffs);
static void ffs_data_get(struct ffs_data *ffs)
{
@@ -2123,7 +2154,6 @@ static void ffs_data_get(struct ffs_data *ffs)
static void ffs_data_opened(struct ffs_data *ffs)
{
refcount_inc(&ffs->ref);
if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
@@ -2148,11 +2178,11 @@ static void ffs_data_put(struct ffs_data *ffs)
static void ffs_data_closed(struct ffs_data *ffs)
{
struct ffs_epfile *epfiles;
unsigned long flags;
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
struct ffs_epfile *epfiles;
unsigned long flags;
ffs->state = FFS_DEACTIVATED;
spin_lock_irqsave(&ffs->eps_lock, flags);
epfiles = ffs->epfiles;
@@ -2161,7 +2191,7 @@ static void ffs_data_closed(struct ffs_data *ffs)
flags);
if (epfiles)
ffs_epfiles_destroy(epfiles,
ffs_epfiles_destroy(ffs->sb, epfiles,
ffs->eps_count);
if (ffs->setup_state == FFS_SETUP_PENDING)
@@ -2171,12 +2201,6 @@ static void ffs_data_closed(struct ffs_data *ffs)
ffs_data_reset(ffs);
}
}
if (atomic_read(&ffs->opened) < 0) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
ffs_data_put(ffs);
}
static struct ffs_data *ffs_data_new(const char *dev_name)
@@ -2226,7 +2250,7 @@ static void ffs_data_clear(struct ffs_data *ffs)
* copy of epfile will save us from use-after-free.
*/
if (epfiles) {
ffs_epfiles_destroy(epfiles, ffs->eps_count);
ffs_epfiles_destroy(ffs->sb, epfiles, ffs->eps_count);
ffs->epfiles = NULL;
}
@@ -2323,6 +2347,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
{
struct ffs_epfile *epfile, *epfiles;
unsigned i, count;
int err;
count = ffs->eps_count;
epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
@@ -2339,12 +2364,11 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
sprintf(epfile->name, "ep%u", i);
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
epfile,
&ffs_epfile_operations);
if (!epfile->dentry) {
ffs_epfiles_destroy(epfiles, i - 1);
return -ENOMEM;
err = ffs_sb_create_file(ffs->sb, epfile->name,
epfile, &ffs_epfile_operations);
if (err) {
ffs_epfiles_destroy(ffs->sb, epfiles, i - 1);
return err;
}
}
@@ -2352,16 +2376,20 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
return 0;
}
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
static void clear_one(struct dentry *dentry)
{
smp_store_release(&dentry->d_inode->i_private, NULL);
}
static void ffs_epfiles_destroy(struct super_block *sb,
struct ffs_epfile *epfiles, unsigned count)
{
struct ffs_epfile *epfile = epfiles;
struct dentry *root = sb->s_root;
for (; count; --count, ++epfile) {
BUG_ON(mutex_is_locked(&epfile->mutex));
if (epfile->dentry) {
simple_recursive_removal(epfile->dentry, NULL);
epfile->dentry = NULL;
}
simple_remove_by_name(root, epfile->name, clear_one);
}
kfree(epfiles);
+23 -26
View File
@@ -150,7 +150,6 @@ struct dev_data {
void *buf;
wait_queue_head_t wait;
struct super_block *sb;
struct dentry *dentry;
/* except this scratch i/o buffer for ep0 */
u8 rbuf[RBUF_SIZE];
@@ -208,7 +207,6 @@ struct ep_data {
struct usb_endpoint_descriptor desc, hs_desc;
struct list_head epfiles;
wait_queue_head_t wait;
struct dentry *dentry;
};
static inline void get_ep (struct ep_data *data)
@@ -1561,16 +1559,12 @@ static void destroy_ep_files (struct dev_data *dev)
spin_lock_irq (&dev->lock);
while (!list_empty(&dev->epfiles)) {
struct ep_data *ep;
struct dentry *dentry;
/* break link to FS */
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles);
spin_unlock_irq (&dev->lock);
dentry = ep->dentry;
ep->dentry = NULL;
/* break link to controller */
mutex_lock(&ep->lock);
if (ep->state == STATE_EP_ENABLED)
@@ -1581,10 +1575,11 @@ static void destroy_ep_files (struct dev_data *dev)
mutex_unlock(&ep->lock);
wake_up (&ep->wait);
put_ep (ep);
/* break link to dcache */
simple_recursive_removal(dentry, NULL);
simple_remove_by_name(dev->sb->s_root, ep->name, NULL);
put_ep (ep);
spin_lock_irq (&dev->lock);
}
@@ -1592,14 +1587,14 @@ static void destroy_ep_files (struct dev_data *dev)
}
static struct dentry *
gadgetfs_create_file (struct super_block *sb, char const *name,
static int gadgetfs_create_file (struct super_block *sb, char const *name,
void *data, const struct file_operations *fops);
static int activate_ep_files (struct dev_data *dev)
{
struct usb_ep *ep;
struct ep_data *data;
int err;
gadget_for_each_ep (ep, dev->gadget) {
@@ -1622,9 +1617,9 @@ static int activate_ep_files (struct dev_data *dev)
if (!data->req)
goto enomem1;
data->dentry = gadgetfs_create_file (dev->sb, data->name,
err = gadgetfs_create_file (dev->sb, data->name,
data, &ep_io_operations);
if (!data->dentry)
if (err)
goto enomem2;
list_add_tail (&data->epfiles, &dev->epfiles);
}
@@ -1988,25 +1983,27 @@ gadgetfs_make_inode (struct super_block *sb,
/* creates in fs root directory, so non-renamable and non-linkable.
* so inode and dentry are paired, until device reconfig.
*/
static struct dentry *
gadgetfs_create_file (struct super_block *sb, char const *name,
static int gadgetfs_create_file (struct super_block *sb, char const *name,
void *data, const struct file_operations *fops)
{
struct dentry *dentry;
struct inode *inode;
dentry = d_alloc_name(sb->s_root, name);
if (!dentry)
return NULL;
inode = gadgetfs_make_inode (sb, data, fops,
S_IFREG | (default_perm & S_IRWXUGO));
if (!inode) {
dput(dentry);
return NULL;
if (!inode)
return -ENOMEM;
dentry = simple_start_creating(sb->s_root, name);
if (IS_ERR(dentry)) {
iput(inode);
return PTR_ERR(dentry);
}
d_add (dentry, inode);
return dentry;
d_make_persistent(dentry, inode);
simple_done_creating(dentry);
return 0;
}
static const struct super_operations gadget_fs_operations = {
@@ -2059,8 +2056,8 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
goto Enomem;
dev->sb = sb;
dev->dentry = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
if (!dev->dentry) {
rc = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
if (rc) {
put_dev(dev);
goto Enomem;
}
@@ -2102,7 +2099,7 @@ static void
gadgetfs_kill_sb (struct super_block *sb)
{
mutex_lock(&sb_mutex);
kill_litter_super (sb);
kill_anon_super (sb);
if (the_device) {
put_dev (the_device);
the_device = NULL;
+1 -1
View File
@@ -88,7 +88,7 @@ static struct file_system_type xenfs_type = {
.owner = THIS_MODULE,
.name = "xenfs",
.init_fs_context = xenfs_init_fs_context,
.kill_sb = kill_litter_super,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("xenfs");
+1 -1
View File
@@ -55,7 +55,7 @@ void autofs_kill_sb(struct super_block *sb)
}
pr_debug("shutting down\n");
kill_litter_super(sb);
kill_anon_super(sb);
if (sbi)
kfree_rcu(sbi, rcu);
}
+4 -7
View File
@@ -602,9 +602,8 @@ static int autofs_dir_symlink(struct mnt_idmap *idmap,
}
inode->i_private = cp;
inode->i_size = size;
d_add(dentry, inode);
dget(dentry);
d_make_persistent(dentry, inode);
p_ino = autofs_dentry_ino(dentry->d_parent);
p_ino->count++;
@@ -631,12 +630,11 @@ static int autofs_dir_symlink(struct mnt_idmap *idmap,
static int autofs_dir_unlink(struct inode *dir, struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
struct autofs_info *ino = autofs_dentry_ino(dentry);
struct autofs_info *p_ino;
p_ino = autofs_dentry_ino(dentry->d_parent);
p_ino->count--;
dput(ino->dentry);
d_make_discardable(dentry);
d_inode(dentry)->i_size = 0;
clear_nlink(d_inode(dentry));
@@ -718,7 +716,7 @@ static int autofs_dir_rmdir(struct inode *dir, struct dentry *dentry)
p_ino = autofs_dentry_ino(dentry->d_parent);
p_ino->count--;
dput(ino->dentry);
d_make_discardable(dentry);
d_inode(dentry)->i_size = 0;
clear_nlink(d_inode(dentry));
@@ -748,12 +746,11 @@ static struct dentry *autofs_dir_mkdir(struct mnt_idmap *idmap,
inode = autofs_get_inode(dir->i_sb, S_IFDIR | mode);
if (!inode)
return ERR_PTR(-ENOMEM);
d_add(dentry, inode);
if (sbi->version < 5)
autofs_set_leaf_automount_flags(dentry);
dget(dentry);
d_make_persistent(dentry, inode);
p_ino = autofs_dentry_ino(dentry->d_parent);
p_ino->count++;
inc_nlink(dir);
+32 -37
View File
@@ -765,14 +765,41 @@ static const struct file_operations bm_entry_operations = {
/* /register */
/* add to filesystem */
static int add_entry(Node *e, struct super_block *sb)
{
struct dentry *dentry = simple_start_creating(sb->s_root, e->name);
struct inode *inode;
struct binfmt_misc *misc;
if (IS_ERR(dentry))
return PTR_ERR(dentry);
inode = bm_get_inode(sb, S_IFREG | 0644);
if (unlikely(!inode)) {
simple_done_creating(dentry);
return -ENOMEM;
}
refcount_set(&e->users, 1);
e->dentry = dentry;
inode->i_private = e;
inode->i_fop = &bm_entry_operations;
d_make_persistent(dentry, inode);
misc = i_binfmt_misc(inode);
write_lock(&misc->entries_lock);
list_add(&e->list, &misc->entries);
write_unlock(&misc->entries_lock);
simple_done_creating(dentry);
return 0;
}
static ssize_t bm_register_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
Node *e;
struct inode *inode;
struct super_block *sb = file_inode(file)->i_sb;
struct dentry *root = sb->s_root, *dentry;
struct binfmt_misc *misc;
int err = 0;
struct file *f = NULL;
@@ -800,39 +827,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
e->interp_file = f;
}
inode_lock(d_inode(root));
dentry = lookup_noperm(&QSTR(e->name), root);
err = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out;
err = -EEXIST;
if (d_really_is_positive(dentry))
goto out2;
inode = bm_get_inode(sb, S_IFREG | 0644);
err = -ENOMEM;
if (!inode)
goto out2;
refcount_set(&e->users, 1);
e->dentry = dget(dentry);
inode->i_private = e;
inode->i_fop = &bm_entry_operations;
d_instantiate(dentry, inode);
misc = i_binfmt_misc(inode);
write_lock(&misc->entries_lock);
list_add(&e->list, &misc->entries);
write_unlock(&misc->entries_lock);
err = 0;
out2:
dput(dentry);
out:
inode_unlock(d_inode(root));
err = add_entry(e, sb);
if (err) {
if (f) {
exe_file_allow_write_access(f);
@@ -1027,7 +1022,7 @@ static struct file_system_type bm_fs_type = {
.name = "binfmt_misc",
.init_fs_context = bm_init_fs_context,
.fs_flags = FS_USERNS_MOUNT,
.kill_sb = kill_litter_super,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("binfmt_misc");
+8 -2
View File
@@ -400,8 +400,14 @@ static void remove_dir(struct dentry * d)
configfs_remove_dirent(d);
if (d_really_is_positive(d))
simple_rmdir(d_inode(parent),d);
if (d_really_is_positive(d)) {
if (likely(simple_empty(d))) {
__simple_rmdir(d_inode(parent),d);
dput(d);
} else {
pr_warn("remove_dir (%pd): attributes remain", d);
}
}
pr_debug(" o %pd removing done (%d)\n", d, d_count(d));
+2 -1
View File
@@ -211,7 +211,8 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
dget_dlock(dentry);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
simple_unlink(d_inode(parent), dentry);
__simple_unlink(d_inode(parent), dentry);
dput(dentry);
} else
spin_unlock(&dentry->d_lock);
}
+1 -1
View File
@@ -116,7 +116,7 @@ static struct file_system_type configfs_fs_type = {
.owner = THIS_MODULE,
.name = "configfs",
.init_fs_context = configfs_init_fs_context,
.kill_sb = kill_litter_super,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("configfs");
+72 -39
View File
@@ -870,6 +870,24 @@ locked:
return false;
}
static void finish_dput(struct dentry *dentry)
__releases(dentry->d_lock)
__releases(RCU)
{
while (lock_for_kill(dentry)) {
rcu_read_unlock();
dentry = __dentry_kill(dentry);
if (!dentry)
return;
if (retain_dentry(dentry, true)) {
spin_unlock(&dentry->d_lock);
return;
}
rcu_read_lock();
}
rcu_read_unlock();
spin_unlock(&dentry->d_lock);
}
/*
* This is dput
@@ -907,22 +925,21 @@ void dput(struct dentry *dentry)
rcu_read_unlock();
return;
}
while (lock_for_kill(dentry)) {
rcu_read_unlock();
dentry = __dentry_kill(dentry);
if (!dentry)
return;
if (retain_dentry(dentry, true)) {
spin_unlock(&dentry->d_lock);
return;
}
rcu_read_lock();
}
rcu_read_unlock();
spin_unlock(&dentry->d_lock);
finish_dput(dentry);
}
EXPORT_SYMBOL(dput);
void d_make_discardable(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
WARN_ON(!(dentry->d_flags & DCACHE_PERSISTENT));
dentry->d_flags &= ~DCACHE_PERSISTENT;
dentry->d_lockref.count--;
rcu_read_lock();
finish_dput(dentry);
}
EXPORT_SYMBOL(d_make_discardable);
static void to_shrink_list(struct dentry *dentry, struct list_head *list)
__must_hold(&dentry->d_lock)
{
@@ -1512,6 +1529,15 @@ out:
return ret;
}
static enum d_walk_ret select_collect_umount(void *_data, struct dentry *dentry)
{
if (dentry->d_flags & DCACHE_PERSISTENT) {
dentry->d_flags &= ~DCACHE_PERSISTENT;
dentry->d_lockref.count--;
}
return select_collect(_data, dentry);
}
static enum d_walk_ret select_collect2(void *_data, struct dentry *dentry)
{
struct select_data *data = _data;
@@ -1540,18 +1566,20 @@ out:
}
/**
* shrink_dcache_parent - prune dcache
* shrink_dcache_tree - prune dcache
* @parent: parent of entries to prune
* @for_umount: true if we want to unpin the persistent ones
*
* Prune the dcache to remove unused children of the parent dentry.
*/
void shrink_dcache_parent(struct dentry *parent)
static void shrink_dcache_tree(struct dentry *parent, bool for_umount)
{
for (;;) {
struct select_data data = {.start = parent};
INIT_LIST_HEAD(&data.dispose);
d_walk(parent, &data, select_collect);
d_walk(parent, &data,
for_umount ? select_collect_umount : select_collect);
if (!list_empty(&data.dispose)) {
shrink_dentry_list(&data.dispose);
@@ -1576,6 +1604,11 @@ void shrink_dcache_parent(struct dentry *parent)
shrink_dentry_list(&data.dispose);
}
}
void shrink_dcache_parent(struct dentry *parent)
{
shrink_dcache_tree(parent, false);
}
EXPORT_SYMBOL(shrink_dcache_parent);
static enum d_walk_ret umount_check(void *_data, struct dentry *dentry)
@@ -1602,7 +1635,7 @@ static enum d_walk_ret umount_check(void *_data, struct dentry *dentry)
static void do_one_tree(struct dentry *dentry)
{
shrink_dcache_parent(dentry);
shrink_dcache_tree(dentry, true);
d_walk(dentry, dentry, umount_check);
d_drop(dentry);
dput(dentry);
@@ -1924,7 +1957,6 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
unsigned add_flags = d_flags_for_inode(inode);
WARN_ON(d_in_lookup(dentry));
spin_lock(&dentry->d_lock);
/*
* The negative counter only tracks dentries on the LRU. Don't dec if
* d_lru is on another list.
@@ -1937,7 +1969,6 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
__d_set_inode_and_type(dentry, inode, add_flags);
raw_write_seqcount_end(&dentry->d_seq);
fsnotify_update_flags(dentry);
spin_unlock(&dentry->d_lock);
}
/**
@@ -1961,7 +1992,9 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
if (inode) {
security_d_instantiate(entry, inode);
spin_lock(&inode->i_lock);
spin_lock(&entry->d_lock);
__d_instantiate(entry, inode);
spin_unlock(&entry->d_lock);
spin_unlock(&inode->i_lock);
}
}
@@ -1980,7 +2013,9 @@ void d_instantiate_new(struct dentry *entry, struct inode *inode)
lockdep_annotate_inode_mutex_key(inode);
security_d_instantiate(entry, inode);
spin_lock(&inode->i_lock);
spin_lock(&entry->d_lock);
__d_instantiate(entry, inode);
spin_unlock(&entry->d_lock);
WARN_ON(!(inode_state_read(inode) & I_NEW));
inode_state_clear(inode, I_NEW | I_CREATING);
inode_wake_up_bit(inode, __I_NEW);
@@ -2742,6 +2777,24 @@ void d_add(struct dentry *entry, struct inode *inode)
}
EXPORT_SYMBOL(d_add);
struct dentry *d_make_persistent(struct dentry *dentry, struct inode *inode)
{
WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
WARN_ON(!inode);
security_d_instantiate(dentry, inode);
spin_lock(&inode->i_lock);
spin_lock(&dentry->d_lock);
__d_instantiate(dentry, inode);
dentry->d_flags |= DCACHE_PERSISTENT;
dget_dlock(dentry);
if (d_unhashed(dentry))
__d_rehash(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
return dentry;
}
EXPORT_SYMBOL(d_make_persistent);
static void swap_names(struct dentry *dentry, struct dentry *target)
{
if (unlikely(dname_external(target))) {
@@ -3111,26 +3164,6 @@ bool is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
}
EXPORT_SYMBOL(is_subdir);
static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry)
{
struct dentry *root = data;
if (dentry != root) {
if (d_unhashed(dentry) || !dentry->d_inode)
return D_WALK_SKIP;
if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
dentry->d_flags |= DCACHE_GENOCIDE;
dentry->d_lockref.count--;
}
}
return D_WALK_CONTINUE;
}
void d_genocide(struct dentry *parent)
{
d_walk(parent, parent, d_genocide_kill);
}
void d_mark_tmpfile(struct file *file, struct inode *inode)
{
struct dentry *dentry = file->f_path.dentry;

Some files were not shown because too many files have changed in this diff Show More