Commit 168e153d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull vfs inode freeing updates from Al Viro:
 "Introduction of separate method for RCU-delayed part of
  ->destroy_inode() (if any).

  Pretty much as posted, except that destroy_inode() stashes
  ->free_inode into the victim (anon-unioned with ->i_fops) before
  scheduling i_callback() and the last two patches (sockfs conversion
  and folding struct socket_wq into struct socket) are excluded - that
  pair should go through netdev once davem reopens his tree"

* 'work.icache' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (58 commits)
  orangefs: make use of ->free_inode()
  shmem: make use of ->free_inode()
  hugetlb: make use of ->free_inode()
  overlayfs: make use of ->free_inode()
  jfs: switch to ->free_inode()
  fuse: switch to ->free_inode()
  ext4: make use of ->free_inode()
  ecryptfs: make use of ->free_inode()
  ceph: use ->free_inode()
  btrfs: use ->free_inode()
  afs: switch to use of ->free_inode()
  dax: make use of ->free_inode()
  ntfs: switch to ->free_inode()
  securityfs: switch to ->free_inode()
  apparmor: switch to ->free_inode()
  rpcpipe: switch to ->free_inode()
  bpf: switch to ->free_inode()
  mqueue: switch to ->free_inode()
  ufs: switch to ->free_inode()
  coda: switch to ->free_inode()
  ...
parents 8ff468c2 f276ae0d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -118,6 +118,7 @@ set: exclusive
--------------------------- super_operations ---------------------------
prototypes:
	struct inode *(*alloc_inode)(struct super_block *sb);
	void (*free_inode)(struct inode *);
	void (*destroy_inode)(struct inode *);
	void (*dirty_inode) (struct inode *, int flags);
	int (*write_inode) (struct inode *, struct writeback_control *wbc);
@@ -139,6 +140,7 @@ locking rules:
	All may block [not true, see below]
			s_umount
alloc_inode:
free_inode:				called from RCU callback
destroy_inode:
dirty_inode:
write_inode:
+25 −0
Original line number Diff line number Diff line
@@ -638,3 +638,28 @@ in your dentry operations instead.
	inode to d_splice_alias() will also do the right thing (equivalent of
	d_add(dentry, NULL); return NULL;), so that kind of special cases
	also doesn't need a separate treatment.
--
[strongly recommended]
	take the RCU-delayed parts of ->destroy_inode() into a new method -
	->free_inode().  If ->destroy_inode() becomes empty - all the better,
	just get rid of it.  Synchronous work (e.g. the stuff that can't
	be done from an RCU callback, or any WARN_ON() where we want the
	stack trace) *might* be movable to ->evict_inode(); however,
	that goes only for the things that are not needed to balance something
	done by ->alloc_inode().  IOW, if it's cleaning up the stuff that
	might have accumulated over the life of in-core inode, ->evict_inode()
	might be a fit.

	Rules for inode destruction:
		* if ->destroy_inode() is non-NULL, it gets called
		* if ->free_inode() is non-NULL, it gets scheduled by call_rcu()
		* combination of NULL ->destroy_inode and NULL ->free_inode is
		  treated as NULL/free_inode_nonrcu, to preserve the compatibility.

	Note that the callback (be it via ->free_inode() or explicit call_rcu()
	in ->destroy_inode()) is *NOT* ordered wrt superblock destruction;
	as the matter of fact, the superblock and all associated structures
	might be already gone.  The filesystem driver is guaranteed to be still
	there, but that's it.  Freeing memory in the callback is fine; doing
	more than that is possible, but requires a lot of care and is best
	avoided.
+2 −8
Original line number Diff line number Diff line
@@ -71,17 +71,11 @@ spufs_alloc_inode(struct super_block *sb)
	return &ei->vfs_inode;
}

static void spufs_i_callback(struct rcu_head *head)
static void spufs_free_inode(struct inode *inode)
{
	struct inode *inode = container_of(head, struct inode, i_rcu);
	kmem_cache_free(spufs_inode_cache, SPUFS_I(inode));
}

static void spufs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, spufs_i_callback);
}

static void
spufs_init_once(void *p)
{
@@ -739,7 +733,7 @@ spufs_fill_super(struct super_block *sb, void *data, int silent)
	struct spufs_sb_info *info;
	static const struct super_operations s_ops = {
		.alloc_inode = spufs_alloc_inode,
		.destroy_inode = spufs_destroy_inode,
		.free_inode = spufs_free_inode,
		.statfs = simple_statfs,
		.evict_inode = spufs_evict_inode,
		.show_options = spufs_show_options,
+2 −5
Original line number Diff line number Diff line
@@ -412,11 +412,9 @@ static struct dax_device *to_dax_dev(struct inode *inode)
	return container_of(inode, struct dax_device, inode);
}

static void dax_i_callback(struct rcu_head *head)
static void dax_free_inode(struct inode *inode)
{
	struct inode *inode = container_of(head, struct inode, i_rcu);
	struct dax_device *dax_dev = to_dax_dev(inode);

	kfree(dax_dev->host);
	dax_dev->host = NULL;
	if (inode->i_rdev)
@@ -427,16 +425,15 @@ static void dax_i_callback(struct rcu_head *head)
static void dax_destroy_inode(struct inode *inode)
{
	struct dax_device *dax_dev = to_dax_dev(inode);

	WARN_ONCE(test_bit(DAXDEV_ALIVE, &dax_dev->flags),
			"kill_dax() must be called before final iput()\n");
	call_rcu(&inode->i_rcu, dax_i_callback);
}

static const struct super_operations dax_sops = {
	.statfs = simple_statfs,
	.alloc_inode = dax_alloc_inode,
	.destroy_inode = dax_destroy_inode,
	.free_inode = dax_free_inode,
	.drop_inode = generic_delete_inode,
};

+2 −8
Original line number Diff line number Diff line
@@ -57,9 +57,8 @@ static struct inode *alloc_inode(struct super_block *sb)
	return &vi->vfs_inode;
}

static void i_callback(struct rcu_head *head)
static void free_inode(struct inode *inode)
{
	struct inode *inode = container_of(head, struct inode, i_rcu);
	struct erofs_vnode *vi = EROFS_V(inode);

	/* be careful RCU symlink path (see ext4_inode_info->i_data)! */
@@ -71,11 +70,6 @@ static void i_callback(struct rcu_head *head)
	kmem_cache_free(erofs_inode_cachep, vi);
}

static void destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, i_callback);
}

static int superblock_read(struct super_block *sb)
{
	struct erofs_sb_info *sbi;
@@ -668,7 +662,7 @@ out:
const struct super_operations erofs_sops = {
	.put_super = erofs_put_super,
	.alloc_inode = alloc_inode,
	.destroy_inode = destroy_inode,
	.free_inode = free_inode,
	.statfs = erofs_statfs,
	.show_options = erofs_show_options,
	.remount_fs = erofs_remount,
Loading