diff options
Diffstat (limited to 'fs/gfs2/sys.c')
| -rw-r--r-- | fs/gfs2/sys.c | 175 | 
1 files changed, 120 insertions, 55 deletions
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 748ccb557c1..3ab566ba569 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -7,6 +7,8 @@   * of the GNU General Public License version 2.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/sched.h>  #include <linux/spinlock.h>  #include <linux/completion.h> @@ -81,7 +83,8 @@ static int gfs2_uuid_valid(const u8 *uuid)  static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf)  { -	const u8 *uuid = sdp->sd_sb.sb_uuid; +	struct super_block *s = sdp->sd_vfs; +	const u8 *uuid = s->s_uuid;  	buf[0] = '\0';  	if (!gfs2_uuid_valid(uuid))  		return 0; @@ -90,39 +93,37 @@ static ssize_t uuid_show(struct gfs2_sbd *sdp, char *buf)  static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)  { -	unsigned int count; - -	mutex_lock(&sdp->sd_freeze_lock); -	count = sdp->sd_freeze_count; -	mutex_unlock(&sdp->sd_freeze_lock); +	struct super_block *sb = sdp->sd_vfs; +	int frozen = (sb->s_writers.frozen == SB_UNFROZEN) ? 0 : 1; -	return snprintf(buf, PAGE_SIZE, "%u\n", count); +	return snprintf(buf, PAGE_SIZE, "%u\n", frozen);  }  static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  { -	ssize_t ret = len; -	int error = 0; +	int error;  	int n = simple_strtol(buf, NULL, 0);  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	switch (n) {  	case 0: -		gfs2_unfreeze_fs(sdp); +		error = thaw_super(sdp->sd_vfs);  		break;  	case 1: -		error = gfs2_freeze_fs(sdp); +		error = freeze_super(sdp->sd_vfs);  		break;  	default: -		ret = -EINVAL; +		return -EINVAL;  	} -	if (error) +	if (error) {  		fs_warn(sdp, "freeze %d error %d", n, error); +		return error; +	} -	return ret; +	return len;  }  static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf) @@ -134,14 +135,13 @@ static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)  static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  {  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	if (simple_strtol(buf, NULL, 0) != 1)  		return -EINVAL; -	gfs2_lm_withdraw(sdp, -		"GFS2: fsid=%s: withdrawing from cluster at user's request\n", -		sdp->sd_fsname); +	gfs2_lm_withdraw(sdp, "withdrawing from cluster at user's request\n"); +  	return len;  } @@ -149,7 +149,7 @@ static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,  				 size_t len)  {  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	if (simple_strtol(buf, NULL, 0) != 1)  		return -EINVAL; @@ -162,42 +162,52 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,  				size_t len)  {  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	if (simple_strtol(buf, NULL, 0) != 1)  		return -EINVAL; -	gfs2_quota_sync(sdp->sd_vfs, 0, 1); +	gfs2_quota_sync(sdp->sd_vfs, 0);  	return len;  }  static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,  					size_t len)  { +	struct kqid qid;  	int error;  	u32 id;  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	id = simple_strtoul(buf, NULL, 0); -	error = gfs2_quota_refresh(sdp, 1, id); +	qid = make_kqid(current_user_ns(), USRQUOTA, id); +	if (!qid_valid(qid)) +		return -EINVAL; + +	error = gfs2_quota_refresh(sdp, qid);  	return error ? error : len;  }  static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,  					 size_t len)  { +	struct kqid qid;  	int error;  	u32 id;  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	id = simple_strtoul(buf, NULL, 0); -	error = gfs2_quota_refresh(sdp, 0, id); +	qid = make_kqid(current_user_ns(), GRPQUOTA, id); +	if (!qid_valid(qid)) +		return -EINVAL; + +	error = gfs2_quota_refresh(sdp, qid);  	return error ? error : len;  } @@ -212,7 +222,7 @@ static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len  	int rv;  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	rv = sscanf(buf, "%u:%llu %15s", &gltype, &glnum,  		    mode); @@ -230,8 +240,8 @@ static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len  	if (gltype > LM_TYPE_JOURNAL)  		return -EINVAL; -	if (gltype == LM_TYPE_NONDISK && glnum == GFS2_TRANS_LOCK) -		glops = &gfs2_trans_glops; +	if (gltype == LM_TYPE_NONDISK && glnum == GFS2_FREEZE_LOCK) +		glops = &gfs2_freeze_glops;  	else  		glops = gfs2_glops_list[gltype];  	if (glops == NULL) @@ -275,7 +285,15 @@ static struct attribute *gfs2_attrs[] = {  	NULL,  }; +static void gfs2_sbd_release(struct kobject *kobj) +{ +	struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); + +	kfree(sdp); +} +  static struct kobj_type gfs2_ktype = { +	.release = gfs2_sbd_release,  	.default_attrs = gfs2_attrs,  	.sysfs_ops     = &gfs2_attr_ops,  }; @@ -297,7 +315,7 @@ static ssize_t block_show(struct gfs2_sbd *sdp, char *buf)  	ssize_t ret;  	int val = 0; -	if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags)) +	if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags))  		val = 1;  	ret = sprintf(buf, "%d\n", val);  	return ret; @@ -312,10 +330,10 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  	val = simple_strtol(buf, NULL, 0);  	if (val == 1) -		set_bit(DFL_BLOCK_LOCKS, &ls->ls_flags); +		set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);  	else if (val == 0) { -		clear_bit(DFL_BLOCK_LOCKS, &ls->ls_flags); -		smp_mb__after_clear_bit(); +		clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags); +		smp_mb__after_atomic();  		gfs2_glock_thaw(sdp);  	} else {  		ret = -EINVAL; @@ -323,6 +341,28 @@ static ssize_t block_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  	return ret;  } +static ssize_t wdack_show(struct gfs2_sbd *sdp, char *buf) +{ +	int val = completion_done(&sdp->sd_wdack) ? 1 : 0; + +	return sprintf(buf, "%d\n", val); +} + +static ssize_t wdack_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ +	ssize_t ret = len; +	int val; + +	val = simple_strtol(buf, NULL, 0); + +	if ((val == 1) && +	    !strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm")) +		complete(&sdp->sd_wdack); +	else +		ret = -EINVAL; +	return ret; +} +  static ssize_t lkfirst_show(struct gfs2_sbd *sdp, char *buf)  {  	struct lm_lockstruct *ls = &sdp->sd_lockstruct; @@ -337,6 +377,9 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  	rv = sscanf(buf, "%u", &first);  	if (rv != 1 || first > 1)  		return -EINVAL; +	rv = wait_for_completion_killable(&sdp->sd_locking_init); +	if (rv) +		return rv;  	spin_lock(&sdp->sd_jindex_spin);  	rv = -EBUSY;  	if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0) @@ -346,8 +389,8 @@ static ssize_t lkfirst_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  		goto out;  	if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)  		goto out; -        sdp->sd_lockstruct.ls_first = first; -        rv = 0; +	sdp->sd_lockstruct.ls_first = first; +	rv = 0;  out:          spin_unlock(&sdp->sd_jindex_spin);          return rv ? rv : len; @@ -356,23 +399,18 @@ out:  static ssize_t first_done_show(struct gfs2_sbd *sdp, char *buf)  {  	struct lm_lockstruct *ls = &sdp->sd_lockstruct; -	return sprintf(buf, "%d\n", ls->ls_first_done); +	return sprintf(buf, "%d\n", !!test_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags));  } -static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)  { -	unsigned jid;  	struct gfs2_jdesc *jd;  	int rv; -	rv = sscanf(buf, "%u", &jid); -	if (rv != 1) -		return -EINVAL; +	/* Wait for our primary journal to be initialized */ +	wait_for_completion(&sdp->sd_journal_ready); -	rv = -ESHUTDOWN;  	spin_lock(&sdp->sd_jindex_spin); -	if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) -		goto out;  	rv = -EBUSY;  	if (sdp->sd_jdesc->jd_jid == jid)  		goto out; @@ -385,6 +423,25 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  	}  out:  	spin_unlock(&sdp->sd_jindex_spin); +	return rv; +} + +static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len) +{ +	unsigned jid; +	int rv; + +	rv = sscanf(buf, "%u", &jid); +	if (rv != 1) +		return -EINVAL; + +	if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) { +		rv = -ESHUTDOWN; +		goto out; +	} + +	rv = gfs2_recover_set(sdp, jid); +out:  	return rv ? rv : len;  } @@ -413,7 +470,9 @@ static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  	rv = sscanf(buf, "%d", &jid);  	if (rv != 1)  		return -EINVAL; - +	rv = wait_for_completion_killable(&sdp->sd_locking_init); +	if (rv) +		return rv;  	spin_lock(&sdp->sd_jindex_spin);  	rv = -EINVAL;  	if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) @@ -426,7 +485,7 @@ static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)  		rv = jid = -EINVAL;  	sdp->sd_lockstruct.ls_jid = jid;  	clear_bit(SDF_NOJOURNALID, &sdp->sd_flags); -	smp_mb__after_clear_bit(); +	smp_mb__after_atomic();  	wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);  out:  	spin_unlock(&sdp->sd_jindex_spin); @@ -438,7 +497,7 @@ static struct gfs2_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)  GDLM_ATTR(proto_name,		0444, proto_name_show,		NULL);  GDLM_ATTR(block,		0644, block_show,		block_store); -GDLM_ATTR(withdraw,		0644, withdraw_show,		withdraw_store); +GDLM_ATTR(withdraw,		0644, wdack_show,		wdack_store);  GDLM_ATTR(jid,			0644, jid_show,			jid_store);  GDLM_ATTR(first,		0644, lkfirst_show,		lkfirst_store);  GDLM_ATTR(first_done,		0444, first_done_show,		NULL); @@ -477,7 +536,7 @@ static ssize_t quota_scale_store(struct gfs2_sbd *sdp, const char *buf,  	unsigned int x, y;  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	if (sscanf(buf, "%u %u", &x, &y) != 2 || !y)  		return -EINVAL; @@ -496,7 +555,7 @@ static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,  	unsigned int x;  	if (!capable(CAP_SYS_ADMIN)) -		return -EACCES; +		return -EPERM;  	x = simple_strtoul(buf, NULL, 0); @@ -532,7 +591,6 @@ TUNE_ATTR(max_readahead, 0);  TUNE_ATTR(complain_secs, 0);  TUNE_ATTR(statfs_slow, 0);  TUNE_ATTR(new_files_jdata, 0); -TUNE_ATTR(quota_simul_sync, 1);  TUNE_ATTR(statfs_quantum, 1);  TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store); @@ -542,7 +600,6 @@ static struct attribute *tune_attrs[] = {  	&tune_attr_max_readahead.attr,  	&tune_attr_complain_secs.attr,  	&tune_attr_statfs_slow.attr, -	&tune_attr_quota_simul_sync.attr,  	&tune_attr_statfs_quantum.attr,  	&tune_attr_quota_scale.attr,  	&tune_attr_new_files_jdata.attr, @@ -566,6 +623,7 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)  	char ro[20];  	char spectator[20];  	char *envp[] = { ro, spectator, NULL }; +	int sysfs_frees_sdp = 0;  	sprintf(ro, "RDONLY=%d", (sb->s_flags & MS_RDONLY) ? 1 : 0);  	sprintf(spectator, "SPECTATOR=%d", sdp->sd_args.ar_spectator ? 1 : 0); @@ -574,8 +632,10 @@ int gfs2_sys_fs_add(struct gfs2_sbd *sdp)  	error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,  				     "%s", sdp->sd_table_name);  	if (error) -		goto fail; +		goto fail_reg; +	sysfs_frees_sdp = 1; /* Freeing sdp is now done by sysfs calling +				function gfs2_sbd_release. */  	error = sysfs_create_group(&sdp->sd_kobj, &tune_group);  	if (error)  		goto fail_reg; @@ -598,9 +658,13 @@ fail_lock_module:  fail_tune:  	sysfs_remove_group(&sdp->sd_kobj, &tune_group);  fail_reg: -	kobject_put(&sdp->sd_kobj); -fail: +	free_percpu(sdp->sd_lkstats);  	fs_err(sdp, "error %d adding sysfs files", error); +	if (sysfs_frees_sdp) +		kobject_put(&sdp->sd_kobj); +	else +		kfree(sdp); +	sb->s_fs_info = NULL;  	return error;  } @@ -616,7 +680,8 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,  		       struct kobj_uevent_env *env)  {  	struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj); -	const u8 *uuid = sdp->sd_sb.sb_uuid; +	struct super_block *s = sdp->sd_vfs; +	const u8 *uuid = s->s_uuid;  	add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);  	add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);  | 
