Commit 69d803c4 authored by Yang Erkun's avatar Yang Erkun Committed by Chuck Lever
Browse files

nfsd: Revert "nfsd: release svc_expkey/svc_export with rcu_work"



This reverts commit f8c989a0.

Before this commit, svc_export_put or expkey_put will call path_put with
sync mode. After this commit, path_put will be called with async mode.
And this can lead the unexpected results show as follow.

mkfs.xfs -f /dev/sda
echo "/ *(rw,no_root_squash,fsid=0)" > /etc/exports
echo "/mnt *(rw,no_root_squash,fsid=1)" >> /etc/exports
exportfs -ra
service nfs-server start
mount -t nfs -o vers=4.0 127.0.0.1:/mnt /mnt1
mount /dev/sda /mnt/sda
touch /mnt1/sda/file
exportfs -r
umount /mnt/sda # failed unexcepted

The touch will finally call nfsd_cross_mnt, add refcount to mount, and
then add cache_head. Before this commit, exportfs -r will call
cache_flush to cleanup all cache_head, and path_put in
svc_export_put/expkey_put will be finished with sync mode. So, the
latter umount will always success. However, after this commit, path_put
will be called with async mode, the latter umount may failed, and if
we add some delay, umount will success too. Personally I think this bug
and should be fixed. We first revert before bugfix patch, and then fix
the original bug with a different way.

Fixes: f8c989a0 ("nfsd: release svc_expkey/svc_export with rcu_work")
Signed-off-by: default avatarYang Erkun <yangerkun@huawei.com>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 583772ee
Loading
Loading
Loading
Loading
+6 −25
Original line number Diff line number Diff line
@@ -40,24 +40,15 @@
#define	EXPKEY_HASHMAX		(1 << EXPKEY_HASHBITS)
#define	EXPKEY_HASHMASK		(EXPKEY_HASHMAX -1)

static void expkey_put_work(struct work_struct *work)
static void expkey_put(struct kref *ref)
{
	struct svc_expkey *key =
		container_of(to_rcu_work(work), struct svc_expkey, ek_rcu_work);
	struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);

	if (test_bit(CACHE_VALID, &key->h.flags) &&
	    !test_bit(CACHE_NEGATIVE, &key->h.flags))
		path_put(&key->ek_path);
	auth_domain_put(key->ek_client);
	kfree(key);
}

static void expkey_put(struct kref *ref)
{
	struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);

	INIT_RCU_WORK(&key->ek_rcu_work, expkey_put_work);
	queue_rcu_work(system_wq, &key->ek_rcu_work);
	kfree_rcu(key, ek_rcu);
}

static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
@@ -364,26 +355,16 @@ static void export_stats_destroy(struct export_stats *stats)
					    EXP_STATS_COUNTERS_NUM);
}

static void svc_export_put_work(struct work_struct *work)
static void svc_export_put(struct kref *ref)
{
	struct svc_export *exp =
		container_of(to_rcu_work(work), struct svc_export, ex_rcu_work);

	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
	path_put(&exp->ex_path);
	auth_domain_put(exp->ex_client);
	nfsd4_fslocs_free(&exp->ex_fslocs);
	export_stats_destroy(exp->ex_stats);
	kfree(exp->ex_stats);
	kfree(exp->ex_uuid);
	kfree(exp);
}

static void svc_export_put(struct kref *ref)
{
	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);

	INIT_RCU_WORK(&exp->ex_rcu_work, svc_export_put_work);
	queue_rcu_work(system_wq, &exp->ex_rcu_work);
	kfree_rcu(exp, ex_rcu);
}

static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
+2 −2
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ struct svc_export {
	u32			ex_layout_types;
	struct nfsd4_deviceid_map *ex_devid_map;
	struct cache_detail	*cd;
	struct rcu_work		ex_rcu_work;
	struct rcu_head		ex_rcu;
	unsigned long		ex_xprtsec_modes;
	struct export_stats	*ex_stats;
};
@@ -92,7 +92,7 @@ struct svc_expkey {
	u32			ek_fsid[6];

	struct path		ek_path;
	struct rcu_work		ek_rcu_work;
	struct rcu_head		ek_rcu;
};

#define EX_ISSYNC(exp)		(!((exp)->ex_flags & NFSEXP_ASYNC))