Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ef818a28 authored by Steve Dickson's avatar Steve Dickson Committed by Trond Myklebust
Browse files

NFS: Stop sillyname renames and unmounts from racing



Added an active/deactive mechanism to the nfs_server structure
allowing async operations to hold off umount until the
operations are done.

Signed-off-by: default avatarSteve Dickson <steved@redhat.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 2f74c0a0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -729,6 +729,9 @@ static struct nfs_server *nfs_alloc_server(void)
	INIT_LIST_HEAD(&server->client_link);
	INIT_LIST_HEAD(&server->master_link);

	init_waitqueue_head(&server->active_wq);
	atomic_set(&server->active, 0);

	server->io_stats = nfs_alloc_iostats();
	if (!server->io_stats) {
		kfree(server);
+2 −0
Original line number Diff line number Diff line
@@ -160,6 +160,8 @@ extern struct rpc_stat nfs_rpcstat;

extern int __init register_nfs_fs(void);
extern void __exit unregister_nfs_fs(void);
extern void nfs_sb_active(struct nfs_server *server);
extern void nfs_sb_deactive(struct nfs_server *server);

/* namespace.c */
extern char *nfs_path(const char *base,
+24 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ static int nfs_get_sb(struct file_system_type *, int, const char *, void *, stru
static int nfs_xdev_get_sb(struct file_system_type *fs_type,
		int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
static void nfs_kill_super(struct super_block *);
static void nfs_put_super(struct super_block *);

static struct file_system_type nfs_fs_type = {
	.owner		= THIS_MODULE,
@@ -223,6 +224,7 @@ static const struct super_operations nfs_sops = {
	.alloc_inode	= nfs_alloc_inode,
	.destroy_inode	= nfs_destroy_inode,
	.write_inode	= nfs_write_inode,
	.put_super	= nfs_put_super,
	.statfs		= nfs_statfs,
	.clear_inode	= nfs_clear_inode,
	.umount_begin	= nfs_umount_begin,
@@ -325,6 +327,28 @@ void __exit unregister_nfs_fs(void)
	unregister_filesystem(&nfs_fs_type);
}

void nfs_sb_active(struct nfs_server *server)
{
	atomic_inc(&server->active);
}

void nfs_sb_deactive(struct nfs_server *server)
{
	if (atomic_dec_and_test(&server->active))
		wake_up(&server->active_wq);
}

static void nfs_put_super(struct super_block *sb)
{
	struct nfs_server *server = NFS_SB(sb);
	/*
	 * Make sure there are no outstanding ops to this server.
	 * If so, wait for them to finish before allowing the
	 * unmount to continue.
	 */
	wait_event(server->active_wq, atomic_read(&server->active) == 0);
}

/*
 * Deliver file system statistics to userspace
 */
+4 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#include <linux/sched.h>
#include <linux/wait.h>

#include "internal.h"

struct nfs_unlinkdata {
	struct hlist_node list;
	struct nfs_removeargs args;
@@ -113,6 +115,7 @@ static void nfs_async_unlink_release(void *calldata)
	struct nfs_unlinkdata	*data = calldata;

	nfs_dec_sillycount(data->dir);
	nfs_sb_deactive(NFS_SERVER(data->dir));
	nfs_free_unlinkdata(data);
}

@@ -153,6 +156,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n
		nfs_dec_sillycount(dir);
		return 0;
	}
	nfs_sb_active(NFS_SERVER(dir));
	data->args.fh = NFS_FH(dir);
	nfs_fattr_init(&data->res.dir_attr);

+6 −0
Original line number Diff line number Diff line
@@ -3,6 +3,9 @@

#include <linux/list.h>
#include <linux/backing-dev.h>
#include <linux/wait.h>

#include <asm/atomic.h>

struct nfs_iostats;

@@ -110,6 +113,9 @@ struct nfs_server {
						   filesystem */
#endif
	void (*destroy)(struct nfs_server *);

	atomic_t active; /* Keep trace of any activity to this server */
	wait_queue_head_t active_wq;  /* Wait for any activity to stop  */
};

/* Server capabilities */