コード例 #1
0
ファイル: util.c プロジェクト: 0xroot/Blackphone-BP1-Kernel
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	const struct lm_lockops *lm = ls->ls_ops;
	va_list args;

	if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW &&
	    test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
		return 0;

	va_start(args, fmt);
	vprintk(fmt, args);
	va_end(args);

	if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
		fs_err(sdp, "about to withdraw this file system\n");
		BUG_ON(sdp->sd_args.ar_debug);

		kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);

		if (lm->lm_unmount) {
			fs_err(sdp, "telling LM to unmount\n");
			lm->lm_unmount(sdp);
		}
		fs_err(sdp, "withdrawn\n");
		dump_stack();
	}

	if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
		panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname);

	return -1;
}
コード例 #2
0
ファイル: super.c プロジェクト: multipath-tcp/mptcp_net-next
static int init_threads(struct gfs2_sbd *sdp)
{
	struct task_struct *p;
	int error = 0;

	p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
	if (IS_ERR(p)) {
		error = PTR_ERR(p);
		fs_err(sdp, "can't start logd thread: %d\n", error);
		return error;
	}
	sdp->sd_logd_process = p;

	p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
	if (IS_ERR(p)) {
		error = PTR_ERR(p);
		fs_err(sdp, "can't start quotad thread: %d\n", error);
		goto fail;
	}
	sdp->sd_quotad_process = p;
	return 0;

fail:
	kthread_stop(sdp->sd_logd_process);
	return error;
}
コード例 #3
0
static void gfs2_write_super_lockfs(struct super_block *sb)
{
	struct gfs2_sbd *sdp = sb->s_fs_info;
	int error;

	if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
		return;

	for (;;) {
		error = gfs2_freeze_fs(sdp);
		if (!error)
			break;

		switch (error) {
		case -EBUSY:
			fs_err(sdp, "waiting for recovery before freeze\n");
			break;

		default:
			fs_err(sdp, "error freezing FS: %d\n", error);
			break;
		}

		fs_err(sdp, "retrying...\n");
		msleep(1000);
	}
}
コード例 #4
0
static int sync_lock(struct gfs2_sbd *sdp, int mode, uint32_t flags,
		     unsigned int num, struct dlm_lksb *lksb, char *name)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	char strname[GDLM_STRNAME_BYTES];
	int error, status;

	memset(strname, 0, GDLM_STRNAME_BYTES);
	snprintf(strname, GDLM_STRNAME_BYTES, "%8x%16x", LM_TYPE_NONDISK, num);

	error = dlm_lock(ls->ls_dlm, mode, lksb, flags,
			 strname, GDLM_STRNAME_BYTES - 1,
			 0, sync_wait_cb, ls, NULL);
	if (error) {
		fs_err(sdp, "%s lkid %x flags %x mode %d error %d\n",
		       name, lksb->sb_lkid, flags, mode, error);
		return error;
	}

	wait_for_completion(&ls->ls_sync_wait);

	status = lksb->sb_status;

	if (status && status != -EAGAIN) {
		fs_err(sdp, "%s lkid %x flags %x mode %d status %d\n",
		       name, lksb->sb_lkid, flags, mode, status);
	}

	return status;
}
コード例 #5
0
static int control_first_done(struct gfs2_sbd *sdp)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	char lvb_bits[GDLM_LVB_SIZE];
	uint32_t start_gen, block_gen;
	int error;

restart:
	spin_lock(&ls->ls_recover_spin);
	start_gen = ls->ls_recover_start;
	block_gen = ls->ls_recover_block;

	if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags) ||
	    !test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
	    !test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
		/*                                 */
		fs_err(sdp, "control_first_done start %u block %u flags %lx\n",
		       start_gen, block_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		control_unlock(sdp);
		return -1;
	}

	if (start_gen == block_gen) {
		/*
                                                            
                                                            
                                                             
                                                                
                                                         
   */
		spin_unlock(&ls->ls_recover_spin);
		fs_info(sdp, "control_first_done wait gen %u\n", start_gen);

		wait_on_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY,
			    dlm_recovery_wait, TASK_UNINTERRUPTIBLE);
		goto restart;
	}

	clear_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
	set_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags);
	memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
	memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
	spin_unlock(&ls->ls_recover_spin);

	memset(lvb_bits, 0, sizeof(lvb_bits));
	control_lvb_write(ls, start_gen, lvb_bits);

	error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT);
	if (error)
		fs_err(sdp, "control_first_done mounted PR error %d\n", error);

	error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
	if (error)
		fs_err(sdp, "control_first_done control NL error %d\n", error);

	return error;
}
コード例 #6
0
static int control_first_done(struct gfs2_sbd *sdp)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	char lvb_bits[GDLM_LVB_SIZE];
	uint32_t start_gen, block_gen;
	int error;

restart:
	spin_lock(&ls->ls_recover_spin);
	start_gen = ls->ls_recover_start;
	block_gen = ls->ls_recover_block;

	if (test_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags) ||
	    !test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
	    !test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
		/* sanity check, should not happen */
		fs_err(sdp, "control_first_done start %u block %u flags %lx\n",
		       start_gen, block_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		control_unlock(sdp);
		return -1;
	}

	if (start_gen == block_gen) {
		/*
		 * Wait for the end of a dlm recovery cycle to switch from
		 * first mounter recovery.  We can ignore any recover_slot
		 * callbacks between the recover_prep and next recover_done
		 * because we are still the first mounter and any failed nodes
		 * have not fully mounted, so they don't need recovery.
		 */
		spin_unlock(&ls->ls_recover_spin);
		fs_info(sdp, "control_first_done wait gen %u\n", start_gen);

		wait_on_bit(&ls->ls_recover_flags, DFL_DLM_RECOVERY,
			    dlm_recovery_wait, TASK_UNINTERRUPTIBLE);
		goto restart;
	}

	clear_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
	set_bit(DFL_FIRST_MOUNT_DONE, &ls->ls_recover_flags);
	memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
	memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
	spin_unlock(&ls->ls_recover_spin);

	memset(lvb_bits, 0, sizeof(lvb_bits));
	control_lvb_write(ls, start_gen, lvb_bits);

	error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT);
	if (error)
		fs_err(sdp, "control_first_done mounted PR error %d\n", error);

	error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
	if (error)
		fs_err(sdp, "control_first_done control NL error %d\n", error);

	return error;
}
コード例 #7
0
ファイル: glops.c プロジェクト: AllenDou/linux
static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
{
	fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
	       bh, (unsigned long long)bh->b_blocknr, bh->b_state,
	       bh->b_page->mapping, bh->b_page->flags);
	fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n",
	       gl->gl_name.ln_type, gl->gl_name.ln_number,
	       gfs2_glock2aspace(gl));
	gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n");
}
コード例 #8
0
static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid,
				 unsigned int result)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;

	if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
		return;

	
	if (jid == ls->ls_jid)
		return;

	spin_lock(&ls->ls_recover_spin);
	if (test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
		spin_unlock(&ls->ls_recover_spin);
		return;
	}
	if (ls->ls_recover_size < jid + 1) {
		fs_err(sdp, "recovery_result jid %d short size %d",
		       jid, ls->ls_recover_size);
		spin_unlock(&ls->ls_recover_spin);
		return;
	}

	fs_info(sdp, "recover jid %d result %s\n", jid,
		result == LM_RD_GAVEUP ? "busy" : "success");

	ls->ls_recover_result[jid] = result;


	if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
		queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work,
				   result == LM_RD_GAVEUP ? HZ : 0);
	spin_unlock(&ls->ls_recover_spin);
}
コード例 #9
0
ファイル: util.c プロジェクト: Lyude/linux
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, const char *fmt, ...)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	const struct lm_lockops *lm = ls->ls_ops;
	va_list args;
	struct va_format vaf;

	if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW &&
	    test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
		return 0;

	if (fmt) {
		va_start(args, fmt);

		vaf.fmt = fmt;
		vaf.va = &args;

		fs_err(sdp, "%pV", &vaf);

		va_end(args);
	}

	if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
		fs_err(sdp, "about to withdraw this file system\n");
		BUG_ON(sdp->sd_args.ar_debug);

		kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);

		if (!strcmp(sdp->sd_lockstruct.ls_ops->lm_proto_name, "lock_dlm"))
			wait_for_completion(&sdp->sd_wdack);

		if (lm->lm_unmount) {
			fs_err(sdp, "telling LM to unmount\n");
			lm->lm_unmount(sdp);
		}
		set_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags);
		fs_err(sdp, "withdrawn\n");
		dump_stack();
	}

	if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
		panic("GFS2: fsid=%s: panic requested\n", sdp->sd_fsname);

	return -1;
}
コード例 #10
0
int gfs2_quotad(void *data)
{
	struct gfs2_sbd *sdp = data;
	unsigned long t;
	int error;

	while (!kthread_should_stop()) {
		/* Update the master statfs file */

		t = sdp->sd_statfs_sync_time +
		    gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;

		if (time_after_eq(jiffies, t)) {
			error = gfs2_statfs_sync(sdp);
			if (error &&
			    error != -EROFS &&
			    !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
				fs_err(sdp, "quotad: (1) error=%d\n", error);
			sdp->sd_statfs_sync_time = jiffies;
		}

		/* Update quota file */

		t = sdp->sd_quota_sync_time +
		    gfs2_tune_get(sdp, gt_quota_quantum) * HZ;

		if (time_after_eq(jiffies, t)) {
			error = gfs2_quota_sync(sdp);
			if (error &&
			    error != -EROFS &&
			    !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
				fs_err(sdp, "quotad: (2) error=%d\n", error);
			sdp->sd_quota_sync_time = jiffies;
		}

		gfs2_quota_scan(sdp);

		t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ;
		if (freezing(current))
			refrigerator();
		schedule_timeout_interruptible(t);
	}

	return 0;
}
コード例 #11
0
int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
{
	va_list args;

	if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
		return 0;

	va_start(args, fmt);
	vprintk(fmt, args);
	va_end(args);

	fs_err(sdp, "about to withdraw this file system\n");
	BUG_ON(sdp->sd_args.ar_debug);

	fs_err(sdp, "telling LM to withdraw\n");
	gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
	fs_err(sdp, "withdrawn\n");
	dump_stack();

	return -1;
}
コード例 #12
0
static void gdlm_first_done(struct gfs2_sbd *sdp)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	int error;

	if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
		return;

	error = control_first_done(sdp);
	if (error)
		fs_err(sdp, "mount first_done error %d\n", error);
}
コード例 #13
0
static int sync_unlock(struct gfs2_sbd *sdp, struct dlm_lksb *lksb, char *name)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	int error;

	error = dlm_unlock(ls->ls_dlm, lksb->sb_lkid, 0, lksb, ls);
	if (error) {
		fs_err(sdp, "%s lkid %x error %d\n",
		       name, lksb->sb_lkid, error);
		return error;
	}

	wait_for_completion(&ls->ls_sync_wait);

	if (lksb->sb_status != -DLM_EUNLOCK) {
		fs_err(sdp, "%s lkid %x status %d\n",
		       name, lksb->sb_lkid, lksb->sb_status);
		return -1;
	}
	return 0;
}
コード例 #14
0
ファイル: util.c プロジェクト: Lyude/linux
void gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
			const char *function, char *file, unsigned int line,
			bool withdraw)
{
	fs_err(sdp,
	       "fatal: I/O error\n"
	       "  block = %llu\n"
	       "  function = %s, file = %s, line = %u\n",
	       (unsigned long long)bh->b_blocknr,
	       function, file, line);
	if (withdraw)
		gfs2_lm_withdraw(sdp, NULL);
}
コード例 #15
0
void gfs2_trans_end(struct gfs2_sbd *sdp)
{
	struct gfs2_trans *tr = current->journal_info;

	BUG_ON(!tr);
	current->journal_info = NULL;

	if (!tr->tr_touched) {
		gfs2_log_release(sdp, tr->tr_reserved);
		if (tr->tr_t_gh.gh_gl) {
			gfs2_glock_dq(&tr->tr_t_gh);
			gfs2_holder_uninit(&tr->tr_t_gh);
			kfree(tr);
		}
		return;
	}

	if (gfs2_assert_withdraw(sdp, tr->tr_num_buf <= tr->tr_blocks)) {
		fs_err(sdp, "tr_num_buf = %u, tr_blocks = %u ",
		       tr->tr_num_buf, tr->tr_blocks);
		print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
	}
	if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) {
		fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u ",
		       tr->tr_num_revoke, tr->tr_revokes);
		print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
	}

	gfs2_log_commit(sdp, tr);
	if (tr->tr_t_gh.gh_gl) {
		gfs2_glock_dq(&tr->tr_t_gh);
		gfs2_holder_uninit(&tr->tr_t_gh);
		kfree(tr);
	}

	if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
		gfs2_log_flush(sdp, NULL);
}
コード例 #16
0
ファイル: lock_dlm.c プロジェクト: avagin/linux
static int make_mode(struct gfs2_sbd *sdp, const unsigned int lmstate)
{
	switch (lmstate) {
	case LM_ST_UNLOCKED:
		return DLM_LOCK_NL;
	case LM_ST_EXCLUSIVE:
		return DLM_LOCK_EX;
	case LM_ST_DEFERRED:
		return DLM_LOCK_CW;
	case LM_ST_SHARED:
		return DLM_LOCK_PR;
	}
	fs_err(sdp, "unknown LM state %d\n", lmstate);
	BUG();
	return -1;
}
コード例 #17
0
ファイル: lock_dlm.c プロジェクト: avagin/linux
static void gdlm_bast(void *arg, int mode)
{
	struct gfs2_glock *gl = arg;

	switch (mode) {
	case DLM_LOCK_EX:
		gfs2_glock_cb(gl, LM_ST_UNLOCKED);
		break;
	case DLM_LOCK_CW:
		gfs2_glock_cb(gl, LM_ST_DEFERRED);
		break;
	case DLM_LOCK_PR:
		gfs2_glock_cb(gl, LM_ST_SHARED);
		break;
	default:
		fs_err(gl->gl_name.ln_sbd, "unknown bast mode %d\n", mode);
		BUG();
	}
}
コード例 #18
0
ファイル: sys.c プロジェクト: liuyang201666/linux-akae
int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
{
    int error;

    sdp->sd_kobj.kset = gfs2_kset;
    error = kobject_init_and_add(&sdp->sd_kobj, &gfs2_ktype, NULL,
                                 "%s", sdp->sd_table_name);
    if (error)
        goto fail;

    error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group);
    if (error)
        goto fail_reg;

    error = sysfs_create_group(&sdp->sd_kobj, &counters_group);
    if (error)
        goto fail_lockstruct;

    error = sysfs_create_group(&sdp->sd_kobj, &args_group);
    if (error)
        goto fail_counters;

    error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
    if (error)
        goto fail_args;

    kobject_uevent(&sdp->sd_kobj, KOBJ_ADD);
    return 0;

fail_args:
    sysfs_remove_group(&sdp->sd_kobj, &args_group);
fail_counters:
    sysfs_remove_group(&sdp->sd_kobj, &counters_group);
fail_lockstruct:
    sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
fail_reg:
    kobject_put(&sdp->sd_kobj);
fail:
    fs_err(sdp, "error %d adding sysfs files", error);
    return error;
}
コード例 #19
0
static void gdlm_recover_slot(void *arg, struct dlm_slot *slot)
{
	struct gfs2_sbd *sdp = arg;
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	int jid = slot->slot - 1;

	spin_lock(&ls->ls_recover_spin);
	if (ls->ls_recover_size < jid + 1) {
		fs_err(sdp, "recover_slot jid %d gen %u short size %d",
		       jid, ls->ls_recover_block, ls->ls_recover_size);
		spin_unlock(&ls->ls_recover_spin);
		return;
	}

	if (ls->ls_recover_submit[jid]) {
		fs_info(sdp, "recover_slot jid %d gen %u prev %u",
			jid, ls->ls_recover_block, ls->ls_recover_submit[jid]);
	}
	ls->ls_recover_submit[jid] = ls->ls_recover_block;
	spin_unlock(&ls->ls_recover_spin);
}
コード例 #20
0
ファイル: sys.c プロジェクト: xf739645524/kernel-rhel5
int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
{
	int error;

	sdp->sd_kobj.kset = &gfs2_kset;
	sdp->sd_kobj.ktype = &gfs2_ktype;

	error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
	if (error)
		goto fail;

	error = kobject_register(&sdp->sd_kobj);
	if (error)
		goto fail;

	error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group);
	if (error)
		goto fail_reg;

	error = sysfs_create_group(&sdp->sd_kobj, &args_group);
	if (error)
		goto fail_lockstruct;

	error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
	if (error)
		goto fail_args;

	return 0;

fail_args:
	sysfs_remove_group(&sdp->sd_kobj, &args_group);
fail_lockstruct:
	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
fail_reg:
	kobject_unregister(&sdp->sd_kobj);
fail:
	fs_err(sdp, "error %d adding sysfs files", error);
	return error;
}
コード例 #21
0
static void gdlm_recovery_result(struct gfs2_sbd *sdp, unsigned int jid,
				 unsigned int result)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;

	if (test_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags))
		return;

	/* don't care about the recovery of own journal during mount */
	if (jid == ls->ls_jid)
		return;

	spin_lock(&ls->ls_recover_spin);
	if (test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
		spin_unlock(&ls->ls_recover_spin);
		return;
	}
	if (ls->ls_recover_size < jid + 1) {
		fs_err(sdp, "recovery_result jid %d short size %d",
		       jid, ls->ls_recover_size);
		spin_unlock(&ls->ls_recover_spin);
		return;
	}

	fs_info(sdp, "recover jid %d result %s\n", jid,
		result == LM_RD_GAVEUP ? "busy" : "success");

	ls->ls_recover_result[jid] = result;

	/* GAVEUP means another node is recovering the journal; delay our
	   next attempt to recover it, to give the other node a chance to
	   finish before trying again */

	if (!test_bit(DFL_UNMOUNT, &ls->ls_recover_flags))
		queue_delayed_work(gfs2_control_wq, &sdp->sd_control_work,
				   result == LM_RD_GAVEUP ? HZ : 0);
	spin_unlock(&ls->ls_recover_spin);
}
コード例 #22
0
ファイル: lock_dlm.c プロジェクト: avagin/linux
static void gdlm_put_lock(struct gfs2_glock *gl)
{
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	int lvb_needs_unlock = 0;
	int error;

	if (gl->gl_lksb.sb_lkid == 0) {
		gfs2_glock_free(gl);
		return;
	}

	clear_bit(GLF_BLOCKING, &gl->gl_flags);
	gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT);
	gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT);
	gfs2_update_request_times(gl);

	/* don't want to skip dlm_unlock writing the lvb when lock is ex */

	if (gl->gl_lksb.sb_lvbptr && (gl->gl_state == LM_ST_EXCLUSIVE))
		lvb_needs_unlock = 1;

	if (test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags) &&
	    !lvb_needs_unlock) {
		gfs2_glock_free(gl);
		return;
	}

	error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK,
			   NULL, gl);
	if (error) {
		fs_err(sdp, "gdlm_unlock %x,%llx err=%d\n",
		       gl->gl_name.ln_type,
		       (unsigned long long)gl->gl_name.ln_number, error);
		return;
	}
}
コード例 #23
0
ファイル: ops_fstype.c プロジェクト: shraddhabarke/linux-iio
static int gfs2_read_sb(struct gfs2_sbd *sdp, int silent)
{
    u32 hash_blocks, ind_blocks, leaf_blocks;
    u32 tmp_blocks;
    unsigned int x;
    int error;

    error = gfs2_read_super(sdp, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift, silent);
    if (error) {
        if (!silent)
            fs_err(sdp, "can't read superblock\n");
        return error;
    }

    sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
                           GFS2_BASIC_BLOCK_SHIFT;
    sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
    sdp->sd_diptrs = (sdp->sd_sb.sb_bsize -
                      sizeof(struct gfs2_dinode)) / sizeof(u64);
    sdp->sd_inptrs = (sdp->sd_sb.sb_bsize -
                      sizeof(struct gfs2_meta_header)) / sizeof(u64);
    sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
    sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2;
    sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1;
    sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(u64);
    sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize -
                            sizeof(struct gfs2_meta_header)) /
                           sizeof(struct gfs2_quota_change);

    /* Compute maximum reservation required to add a entry to a directory */

    hash_blocks = DIV_ROUND_UP(sizeof(u64) * (1 << GFS2_DIR_MAX_DEPTH),
                               sdp->sd_jbsize);

    ind_blocks = 0;
    for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) {
        tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs);
        ind_blocks += tmp_blocks;
    }

    leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH;

    sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;

    sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize -
                            sizeof(struct gfs2_dinode);
    sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs;
    for (x = 2;; x++) {
        u64 space, d;
        u32 m;

        space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs;
        d = space;
        m = do_div(d, sdp->sd_inptrs);

        if (d != sdp->sd_heightsize[x - 1] || m)
            break;
        sdp->sd_heightsize[x] = space;
    }
    sdp->sd_max_height = x;
    sdp->sd_heightsize[x] = ~0;
    gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);

    sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
                             sizeof(struct gfs2_dinode);
    sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
    for (x = 2;; x++) {
        u64 space, d;
        u32 m;

        space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
        d = space;
        m = do_div(d, sdp->sd_inptrs);

        if (d != sdp->sd_jheightsize[x - 1] || m)
            break;
        sdp->sd_jheightsize[x] = space;
    }
    sdp->sd_max_jheight = x;
    sdp->sd_jheightsize[x] = ~0;
    gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);

    return 0;
}
コード例 #24
0
static int control_mount(struct gfs2_sbd *sdp)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	char lvb_bits[GDLM_LVB_SIZE];
	uint32_t start_gen, block_gen, mount_gen, lvb_gen;
	int mounted_mode;
	int retries = 0;
	int error;

	memset(&ls->ls_mounted_lksb, 0, sizeof(struct dlm_lksb));
	memset(&ls->ls_control_lksb, 0, sizeof(struct dlm_lksb));
	memset(&ls->ls_control_lvb, 0, GDLM_LVB_SIZE);
	ls->ls_control_lksb.sb_lvbptr = ls->ls_control_lvb;
	init_completion(&ls->ls_sync_wait);

	set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);

	error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_VALBLK);
	if (error) {
		fs_err(sdp, "control_mount control_lock NL error %d\n", error);
		return error;
	}

	error = mounted_lock(sdp, DLM_LOCK_NL, 0);
	if (error) {
		fs_err(sdp, "control_mount mounted_lock NL error %d\n", error);
		control_unlock(sdp);
		return error;
	}
	mounted_mode = DLM_LOCK_NL;

restart:
	if (retries++ && signal_pending(current)) {
		error = -EINTR;
		goto fail;
	}


	if (mounted_mode != DLM_LOCK_NL) {
		error = mounted_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
		if (error)
			goto fail;
		mounted_mode = DLM_LOCK_NL;
	}


	msleep_interruptible(500);


	error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE|DLM_LKF_VALBLK);
	if (error == -EAGAIN) {
		goto restart;
	} else if (error) {
		fs_err(sdp, "control_mount control_lock EX error %d\n", error);
		goto fail;
	}

	error = mounted_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
	if (!error) {
		mounted_mode = DLM_LOCK_EX;
		goto locks_done;
	} else if (error != -EAGAIN) {
		fs_err(sdp, "control_mount mounted_lock EX error %d\n", error);
		goto fail;
	}

	error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
	if (!error) {
		mounted_mode = DLM_LOCK_PR;
		goto locks_done;
	} else {
		
		fs_err(sdp, "control_mount mounted_lock PR error %d\n", error);
		goto fail;
	}

locks_done:

	control_lvb_read(ls, &lvb_gen, lvb_bits);

	if (lvb_gen == 0xFFFFFFFF) {
		
		fs_err(sdp, "control_mount control_lock disabled\n");
		error = -EINVAL;
		goto fail;
	}

	if (mounted_mode == DLM_LOCK_EX) {
		
		spin_lock(&ls->ls_recover_spin);
		clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
		set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
		set_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		fs_info(sdp, "first mounter control generation %u\n", lvb_gen);
		return 0;
	}

	error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
	if (error)
		goto fail;


	if (!all_jid_bits_clear(lvb_bits)) {
		
		fs_info(sdp, "control_mount wait for journal recovery\n");
		goto restart;
	}

	spin_lock(&ls->ls_recover_spin);
	block_gen = ls->ls_recover_block;
	start_gen = ls->ls_recover_start;
	mount_gen = ls->ls_recover_mount;

	if (lvb_gen < mount_gen) {
		fs_info(sdp, "control_mount wait1 block %u start %u mount %u "
			"lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
			lvb_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		goto restart;
	}

	if (lvb_gen != start_gen) {
		fs_info(sdp, "control_mount wait2 block %u start %u mount %u "
			"lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
			lvb_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		goto restart;
	}

	if (block_gen == start_gen) {
		
		fs_info(sdp, "control_mount wait3 block %u start %u mount %u "
			"lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
			lvb_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		goto restart;
	}

	clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
	set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
	memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
	memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
	spin_unlock(&ls->ls_recover_spin);
	return 0;

fail:
	mounted_unlock(sdp);
	control_unlock(sdp);
	return error;
}
コード例 #25
0
static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	char cluster[GFS2_LOCKNAME_LEN];
	const char *fsname;
	uint32_t flags;
	int error, ops_result;


	INIT_DELAYED_WORK(&sdp->sd_control_work, gfs2_control_func);
	spin_lock_init(&ls->ls_recover_spin);
	ls->ls_recover_flags = 0;
	ls->ls_recover_mount = 0;
	ls->ls_recover_start = 0;
	ls->ls_recover_block = 0;
	ls->ls_recover_size = 0;
	ls->ls_recover_submit = NULL;
	ls->ls_recover_result = NULL;

	error = set_recover_size(sdp, NULL, 0);
	if (error)
		goto fail;


	fsname = strchr(table, ':');
	if (!fsname) {
		fs_info(sdp, "no fsname found\n");
		error = -EINVAL;
		goto fail_free;
	}
	memset(cluster, 0, sizeof(cluster));
	memcpy(cluster, table, strlen(table) - strlen(fsname));
	fsname++;

	flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL;
	if (ls->ls_nodir)
		flags |= DLM_LSFL_NODIR;


	error = dlm_new_lockspace(fsname, cluster, flags, GDLM_LVB_SIZE,
				  &gdlm_lockspace_ops, sdp, &ops_result,
				  &ls->ls_dlm);
	if (error) {
		fs_err(sdp, "dlm_new_lockspace error %d\n", error);
		goto fail_free;
	}

	if (ops_result < 0) {
		fs_info(sdp, "dlm lockspace ops not used\n");
		free_recover_size(ls);
		set_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags);
		return 0;
	}

	if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags)) {
		fs_err(sdp, "dlm lockspace ops disallow jid preset\n");
		error = -EINVAL;
		goto fail_release;
	}


	error = control_mount(sdp);
	if (error) {
		fs_err(sdp, "mount control error %d\n", error);
		goto fail_release;
	}

	ls->ls_first = !!test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
	clear_bit(SDF_NOJOURNALID, &sdp->sd_flags);
	smp_mb__after_clear_bit();
	wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
	return 0;

fail_release:
	dlm_release_lockspace(ls->ls_dlm, 2);
fail_free:
	free_recover_size(ls);
fail:
	return error;
}
コード例 #26
0
static int gfs2_bmap_alloc(struct inode *inode, const sector_t lblock,
			   struct buffer_head *bh_map, struct metapath *mp,
			   const unsigned int sheight,
			   const unsigned int height,
			   const unsigned int maxlen)
{
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct super_block *sb = sdp->sd_vfs;
	struct buffer_head *dibh = mp->mp_bh[0];
	u64 bn, dblock = 0;
	unsigned n, i, blks, alloced = 0, iblks = 0, branch_start = 0;
	unsigned dblks = 0;
	unsigned ptrs_per_blk;
	const unsigned end_of_metadata = height - 1;
	int ret;
	int eob = 0;
	enum alloc_state state;
	__be64 *ptr;
	__be64 zero_bn = 0;

	BUG_ON(sheight < 1);
	BUG_ON(dibh == NULL);

	gfs2_trans_add_bh(ip->i_gl, dibh, 1);

	if (height == sheight) {
		struct buffer_head *bh;
		
		ptr = metapointer(end_of_metadata, mp);
		bh = mp->mp_bh[end_of_metadata];
		dblks = gfs2_extent_length(bh->b_data, bh->b_size, ptr, maxlen,
					   &eob);
		BUG_ON(dblks < 1);
		state = ALLOC_DATA;
	} else {
		
		ptrs_per_blk = height > 1 ? sdp->sd_inptrs : sdp->sd_diptrs;
		dblks = min(maxlen, ptrs_per_blk - mp->mp_list[end_of_metadata]);
		if (height == ip->i_height) {
			
			iblks = height - sheight;
			state = ALLOC_GROW_DEPTH;
		} else {
			
			state = ALLOC_GROW_HEIGHT;
			iblks = height - ip->i_height;
			branch_start = metapath_branch_start(mp);
			iblks += (height - branch_start);
		}
	}

	

	blks = dblks + iblks;
	i = sheight;
	do {
		int error;
		n = blks - alloced;
		error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL);
		if (error)
			return error;
		alloced += n;
		if (state != ALLOC_DATA || gfs2_is_jdata(ip))
			gfs2_trans_add_unrevoke(sdp, bn, n);
		switch (state) {
		
		case ALLOC_GROW_HEIGHT:
			if (i == 1) {
				ptr = (__be64 *)(dibh->b_data +
						 sizeof(struct gfs2_dinode));
				zero_bn = *ptr;
			}
			for (; i - 1 < height - ip->i_height && n > 0; i++, n--)
				gfs2_indirect_init(mp, ip->i_gl, i, 0, bn++);
			if (i - 1 == height - ip->i_height) {
				i--;
				gfs2_buffer_copy_tail(mp->mp_bh[i],
						sizeof(struct gfs2_meta_header),
						dibh, sizeof(struct gfs2_dinode));
				gfs2_buffer_clear_tail(dibh,
						sizeof(struct gfs2_dinode) +
						sizeof(__be64));
				ptr = (__be64 *)(mp->mp_bh[i]->b_data +
					sizeof(struct gfs2_meta_header));
				*ptr = zero_bn;
				state = ALLOC_GROW_DEPTH;
				for(i = branch_start; i < height; i++) {
					if (mp->mp_bh[i] == NULL)
						break;
					brelse(mp->mp_bh[i]);
					mp->mp_bh[i] = NULL;
				}
				i = branch_start;
			}
			if (n == 0)
				break;
		
		case ALLOC_GROW_DEPTH:
			if (i > 1 && i < height)
				gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[i-1], 1);
			for (; i < height && n > 0; i++, n--)
				gfs2_indirect_init(mp, ip->i_gl, i,
						   mp->mp_list[i-1], bn++);
			if (i == height)
				state = ALLOC_DATA;
			if (n == 0)
				break;
		
		case ALLOC_DATA:
			BUG_ON(n > dblks);
			BUG_ON(mp->mp_bh[end_of_metadata] == NULL);
			gfs2_trans_add_bh(ip->i_gl, mp->mp_bh[end_of_metadata], 1);
			dblks = n;
			ptr = metapointer(end_of_metadata, mp);
			dblock = bn;
			while (n-- > 0)
				*ptr++ = cpu_to_be64(bn++);
			if (buffer_zeronew(bh_map)) {
				ret = sb_issue_zeroout(sb, dblock, dblks,
						       GFP_NOFS);
				if (ret) {
					fs_err(sdp,
					       "Failed to zero data buffers\n");
					clear_buffer_zeronew(bh_map);
				}
			}
			break;
		}
	} while ((state != ALLOC_DATA) || !dblock);

	ip->i_height = height;
	gfs2_add_inode_blocks(&ip->i_inode, alloced);
	gfs2_dinode_out(ip, mp->mp_bh[0]->b_data);
	map_bh(bh_map, inode->i_sb, dblock);
	bh_map->b_size = dblks << inode->i_blkbits;
	set_buffer_new(bh_map);
	return 0;
}
コード例 #27
0
ファイル: fs32_chdir.c プロジェクト: OS2World/DRV-ext2
/*
 * struct fs32_chdir_parms {
 *     unsigned short      iCurDirEnd;
 *     PTR16               pDir;
 *     PTR16               pcdfsd;
 *     PTR16               pcdfsi;
 *     unsigned short      flag;
 * };
 */
int FS32ENTRY fs32_chdir(struct fs32_chdir_parms *parms)
{
    char *pDir;
    struct cdfsi32 *pcdfsi;
    union cdfsd32 *pcdfsd;
    int rc;
    struct file *p_file;
    struct super_block *sb;
    int valid;
    char *tmp;
    struct inode *base;

    switch (parms->flag)
    {
        case CD_EXPLICIT:
            pcdfsi = VDHQueryLin(parms->pcdfsi);
            pcdfsd = VDHQueryLin(parms->pcdfsd);
            pDir = VDHQueryLin(parms->pDir);

            if (trace_FS_CHDIR)
            {
                kernel_printf("FS_CHDIR( CD_EXPLICIT, %s )", pDir);
            }

            rc = ERROR_INVALID_PARAMETER;
            if (parms->iCurDirEnd != CURDIREND_INVALID)
            {
                tmp = pDir + parms->iCurDirEnd;
                if ((pcdfsd->u.p_file) && (pcdfsd->u.p_file->f_magic == FILE_MAGIC))
                {
                    base = pcdfsd->u.p_file->f_inode;
                    if (base)
                    {
                        rc = NO_ERROR;
                    }
                }
            }
            else
            {
                sb = getvolume(pcdfsi->cdi_hVPB);
                if ((sb) && (sb->s_magic_internal == SUPER_MAGIC))
                {
                    tmp = skip_drive(pDir);
                    base = sb->s_mounted;
                    if (base)
                    {
                        rc = NO_ERROR;
                    }
                }
            }

            if (rc == NO_ERROR)
            {
                if ((p_file = open_by_name(base, tmp, OPENMODE_READONLY)) == 0)
                {
                    rc = ERROR_PATH_NOT_FOUND;
                }
                else
                {
                    if (!S_ISDIR(p_file->f_inode->i_mode))
                    {
                        kernel_printf("FS_CHDIR( %s ) Not a directory", pDir);
                        vfs_close(p_file);
                        rc = ERROR_ACCESS_DENIED;
                    }
                    else
                    {
                        pcdfsd->u.is_valid = 1;
                        pcdfsd->u.p_file = p_file;
                        rc = NO_ERROR;
                    }
                }
            }
            break;

        case CD_VERIFY:
            pcdfsi = VDHQueryLin(parms->pcdfsi);
            pcdfsd = VDHQueryLin(parms->pcdfsd);

            if (trace_FS_CHDIR)
            {
                kernel_printf("FS_CHDIR : flag = CD_VERIFY hVPB=0x%04X", pcdfsi->cdi_hVPB);
            }

            //
            // Gets the superblock from pcdfsi
            //
            sb = getvolume(pcdfsi->cdi_hVPB);
            valid = 1;
            if ((p_file = open_by_name(sb->s_mounted, skip_drive(pcdfsi->cdi_curdir), OPENMODE_READONLY)) == 0)
            {
                valid = 0;
            }
            else
            {
                if (!S_ISDIR(p_file->f_inode->i_mode))
                {
                    vfs_close(p_file);
                    valid = 0;
                }

                if (pcdfsi->cdi_flags & CDI_ISVALID)
                {
                    vfs_close(pcdfsd->u.p_file);
                }
                if (valid)
                {
                    pcdfsd->u.is_valid = 1;
                    pcdfsd->u.p_file = p_file;
                    return NO_ERROR;
                }
                else
                {
                    vfs_close(p_file);
                    return ERROR_PATH_NOT_FOUND;
                }
            }
            break;

        case CD_FREE:
            pcdfsd = VDHQueryLin(parms->pcdfsd);

            if (trace_FS_CHDIR)
            {
                kernel_printf("FS_CHDIR( CD_FREE )");
            }


            if (pcdfsd->u.is_valid == 1)
            {
                pcdfsd->u.is_valid = 0;
                if ((rc = vfs_close(pcdfsd->u.p_file)) != NO_ERROR)
                {
                    fs_err(FUNC_FS_CHDIR, FUNC_CLOSE, rc, THISFILE, __LINE__);
                }
//                return rc;
            }
            else
            {
                rc = NO_ERROR;
            }
            break;

        default:
            fs_log("FS_CHDIR : invalid flag");
            rc = ERROR_INVALID_PARAMETER;

    }

    return rc;
}
コード例 #28
0
static int control_mount(struct gfs2_sbd *sdp)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	uint32_t start_gen, block_gen, mount_gen, lvb_gen;
	int mounted_mode;
	int retries = 0;
	int error;

	memset(&ls->ls_mounted_lksb, 0, sizeof(struct dlm_lksb));
	memset(&ls->ls_control_lksb, 0, sizeof(struct dlm_lksb));
	memset(&ls->ls_control_lvb, 0, GDLM_LVB_SIZE);
	ls->ls_control_lksb.sb_lvbptr = ls->ls_control_lvb;
	init_completion(&ls->ls_sync_wait);

	set_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);

	error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_VALBLK);
	if (error) {
		fs_err(sdp, "control_mount control_lock NL error %d\n", error);
		return error;
	}

	error = mounted_lock(sdp, DLM_LOCK_NL, 0);
	if (error) {
		fs_err(sdp, "control_mount mounted_lock NL error %d\n", error);
		control_unlock(sdp);
		return error;
	}
	mounted_mode = DLM_LOCK_NL;

restart:
	if (retries++ && signal_pending(current)) {
		error = -EINTR;
		goto fail;
	}

	/*
	 * We always start with both locks in NL. control_lock is
	 * demoted to NL below so we don't need to do it here.
	 */

	if (mounted_mode != DLM_LOCK_NL) {
		error = mounted_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
		if (error)
			goto fail;
		mounted_mode = DLM_LOCK_NL;
	}

	/*
	 * Other nodes need to do some work in dlm recovery and gfs2_control
	 * before the recover_done and control_lock will be ready for us below.
	 * A delay here is not required but often avoids having to retry.
	 */

	msleep_interruptible(500);

	/*
	 * Acquire control_lock in EX and mounted_lock in either EX or PR.
	 * control_lock lvb keeps track of any pending journal recoveries.
	 * mounted_lock indicates if any other nodes have the fs mounted.
	 */

	error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE|DLM_LKF_VALBLK);
	if (error == -EAGAIN) {
		goto restart;
	} else if (error) {
		fs_err(sdp, "control_mount control_lock EX error %d\n", error);
		goto fail;
	}

	error = mounted_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
	if (!error) {
		mounted_mode = DLM_LOCK_EX;
		goto locks_done;
	} else if (error != -EAGAIN) {
		fs_err(sdp, "control_mount mounted_lock EX error %d\n", error);
		goto fail;
	}

	error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT|DLM_LKF_NOQUEUE);
	if (!error) {
		mounted_mode = DLM_LOCK_PR;
		goto locks_done;
	} else {
		/* not even -EAGAIN should happen here */
		fs_err(sdp, "control_mount mounted_lock PR error %d\n", error);
		goto fail;
	}

locks_done:
	/*
	 * If we got both locks above in EX, then we're the first mounter.
	 * If not, then we need to wait for the control_lock lvb to be
	 * updated by other mounted nodes to reflect our mount generation.
	 *
	 * In simple first mounter cases, first mounter will see zero lvb_gen,
	 * but in cases where all existing nodes leave/fail before mounting
	 * nodes finish control_mount, then all nodes will be mounting and
	 * lvb_gen will be non-zero.
	 */

	control_lvb_read(ls, &lvb_gen, ls->ls_lvb_bits);

	if (lvb_gen == 0xFFFFFFFF) {
		/* special value to force mount attempts to fail */
		fs_err(sdp, "control_mount control_lock disabled\n");
		error = -EINVAL;
		goto fail;
	}

	if (mounted_mode == DLM_LOCK_EX) {
		/* first mounter, keep both EX while doing first recovery */
		spin_lock(&ls->ls_recover_spin);
		clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
		set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
		set_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		fs_info(sdp, "first mounter control generation %u\n", lvb_gen);
		return 0;
	}

	error = control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
	if (error)
		goto fail;

	/*
	 * We are not first mounter, now we need to wait for the control_lock
	 * lvb generation to be >= the generation from our first recover_done
	 * and all lvb bits to be clear (no pending journal recoveries.)
	 */

	if (!all_jid_bits_clear(ls->ls_lvb_bits)) {
		/* journals need recovery, wait until all are clear */
		fs_info(sdp, "control_mount wait for journal recovery\n");
		goto restart;
	}

	spin_lock(&ls->ls_recover_spin);
	block_gen = ls->ls_recover_block;
	start_gen = ls->ls_recover_start;
	mount_gen = ls->ls_recover_mount;

	if (lvb_gen < mount_gen) {
		/* wait for mounted nodes to update control_lock lvb to our
		   generation, which might include new recovery bits set */
		fs_info(sdp, "control_mount wait1 block %u start %u mount %u "
			"lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
			lvb_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		goto restart;
	}

	if (lvb_gen != start_gen) {
		/* wait for mounted nodes to update control_lock lvb to the
		   latest recovery generation */
		fs_info(sdp, "control_mount wait2 block %u start %u mount %u "
			"lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
			lvb_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		goto restart;
	}

	if (block_gen == start_gen) {
		/* dlm recovery in progress, wait for it to finish */
		fs_info(sdp, "control_mount wait3 block %u start %u mount %u "
			"lvb %u flags %lx\n", block_gen, start_gen, mount_gen,
			lvb_gen, ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		goto restart;
	}

	clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
	set_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags);
	memset(ls->ls_recover_submit, 0, ls->ls_recover_size*sizeof(uint32_t));
	memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
	spin_unlock(&ls->ls_recover_spin);
	return 0;

fail:
	mounted_unlock(sdp);
	control_unlock(sdp);
	return error;
}
コード例 #29
0
static void gfs2_control_func(struct work_struct *work)
{
	struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	uint32_t block_gen, start_gen, lvb_gen, flags;
	int recover_set = 0;
	int write_lvb = 0;
	int recover_size;
	int i, error;

	spin_lock(&ls->ls_recover_spin);
	/*
	 * No MOUNT_DONE means we're still mounting; control_mount()
	 * will set this flag, after which this thread will take over
	 * all further clearing of BLOCK_LOCKS.
	 *
	 * FIRST_MOUNT means this node is doing first mounter recovery,
	 * for which recovery control is handled by
	 * control_mount()/control_first_done(), not this thread.
	 */
	if (!test_bit(DFL_MOUNT_DONE, &ls->ls_recover_flags) ||
	     test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags)) {
		spin_unlock(&ls->ls_recover_spin);
		return;
	}
	block_gen = ls->ls_recover_block;
	start_gen = ls->ls_recover_start;
	spin_unlock(&ls->ls_recover_spin);

	/*
	 * Equal block_gen and start_gen implies we are between
	 * recover_prep and recover_done callbacks, which means
	 * dlm recovery is in progress and dlm locking is blocked.
	 * There's no point trying to do any work until recover_done.
	 */

	if (block_gen == start_gen)
		return;

	/*
	 * Propagate recover_submit[] and recover_result[] to lvb:
	 * dlm_recoverd adds to recover_submit[] jids needing recovery
	 * gfs2_recover adds to recover_result[] journal recovery results
	 *
	 * set lvb bit for jids in recover_submit[] if the lvb has not
	 * yet been updated for the generation of the failure
	 *
	 * clear lvb bit for jids in recover_result[] if the result of
	 * the journal recovery is SUCCESS
	 */

	error = control_lock(sdp, DLM_LOCK_EX, DLM_LKF_CONVERT|DLM_LKF_VALBLK);
	if (error) {
		fs_err(sdp, "control lock EX error %d\n", error);
		return;
	}

	control_lvb_read(ls, &lvb_gen, ls->ls_lvb_bits);

	spin_lock(&ls->ls_recover_spin);
	if (block_gen != ls->ls_recover_block ||
	    start_gen != ls->ls_recover_start) {
		fs_info(sdp, "recover generation %u block1 %u %u\n",
			start_gen, block_gen, ls->ls_recover_block);
		spin_unlock(&ls->ls_recover_spin);
		control_lock(sdp, DLM_LOCK_NL, DLM_LKF_CONVERT);
		return;
	}

	recover_size = ls->ls_recover_size;

	if (lvb_gen <= start_gen) {
		/*
		 * Clear lvb bits for jids we've successfully recovered.
		 * Because all nodes attempt to recover failed journals,
		 * a journal can be recovered multiple times successfully
		 * in succession.  Only the first will really do recovery,
		 * the others find it clean, but still report a successful
		 * recovery.  So, another node may have already recovered
		 * the jid and cleared the lvb bit for it.
		 */
		for (i = 0; i < recover_size; i++) {
			if (ls->ls_recover_result[i] != LM_RD_SUCCESS)
				continue;

			ls->ls_recover_result[i] = 0;

			if (!test_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET))
				continue;

			__clear_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET);
			write_lvb = 1;
		}
	}

	if (lvb_gen == start_gen) {
		/*
		 * Failed slots before start_gen are already set in lvb.
		 */
		for (i = 0; i < recover_size; i++) {
			if (!ls->ls_recover_submit[i])
				continue;
			if (ls->ls_recover_submit[i] < lvb_gen)
				ls->ls_recover_submit[i] = 0;
		}
	} else if (lvb_gen < start_gen) {
		/*
		 * Failed slots before start_gen are not yet set in lvb.
		 */
		for (i = 0; i < recover_size; i++) {
			if (!ls->ls_recover_submit[i])
				continue;
			if (ls->ls_recover_submit[i] < start_gen) {
				ls->ls_recover_submit[i] = 0;
				__set_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET);
			}
		}
		/* even if there are no bits to set, we need to write the
		   latest generation to the lvb */
		write_lvb = 1;
	} else {
		/*
		 * we should be getting a recover_done() for lvb_gen soon
		 */
	}
	spin_unlock(&ls->ls_recover_spin);

	if (write_lvb) {
		control_lvb_write(ls, start_gen, ls->ls_lvb_bits);
		flags = DLM_LKF_CONVERT | DLM_LKF_VALBLK;
	} else {
		flags = DLM_LKF_CONVERT;
	}

	error = control_lock(sdp, DLM_LOCK_NL, flags);
	if (error) {
		fs_err(sdp, "control lock NL error %d\n", error);
		return;
	}

	/*
	 * Everyone will see jid bits set in the lvb, run gfs2_recover_set(),
	 * and clear a jid bit in the lvb if the recovery is a success.
	 * Eventually all journals will be recovered, all jid bits will
	 * be cleared in the lvb, and everyone will clear BLOCK_LOCKS.
	 */

	for (i = 0; i < recover_size; i++) {
		if (test_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET)) {
			fs_info(sdp, "recover generation %u jid %d\n",
				start_gen, i);
			gfs2_recover_set(sdp, i);
			recover_set++;
		}
	}
	if (recover_set)
		return;

	/*
	 * No more jid bits set in lvb, all recovery is done, unblock locks
	 * (unless a new recover_prep callback has occured blocking locks
	 * again while working above)
	 */

	spin_lock(&ls->ls_recover_spin);
	if (ls->ls_recover_block == block_gen &&
	    ls->ls_recover_start == start_gen) {
		clear_bit(DFL_BLOCK_LOCKS, &ls->ls_recover_flags);
		spin_unlock(&ls->ls_recover_spin);
		fs_info(sdp, "recover generation %u done\n", start_gen);
		gfs2_glock_thaw(sdp);
	} else {
		fs_info(sdp, "recover generation %u block2 %u %u\n",
			start_gen, block_gen, ls->ls_recover_block);
		spin_unlock(&ls->ls_recover_spin);
	}
}
コード例 #30
0
static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
{
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	char cluster[GFS2_LOCKNAME_LEN];
	const char *fsname;
	uint32_t flags;
	int error, ops_result;

	/*
	 * initialize everything
	 */

	INIT_DELAYED_WORK(&sdp->sd_control_work, gfs2_control_func);
	spin_lock_init(&ls->ls_recover_spin);
	ls->ls_recover_flags = 0;
	ls->ls_recover_mount = 0;
	ls->ls_recover_start = 0;
	ls->ls_recover_block = 0;
	ls->ls_recover_size = 0;
	ls->ls_recover_submit = NULL;
	ls->ls_recover_result = NULL;
	ls->ls_lvb_bits = NULL;

	error = set_recover_size(sdp, NULL, 0);
	if (error)
		goto fail;

	/*
	 * prepare dlm_new_lockspace args
	 */

	fsname = strchr(table, ':');
	if (!fsname) {
		fs_info(sdp, "no fsname found\n");
		error = -EINVAL;
		goto fail_free;
	}
	memset(cluster, 0, sizeof(cluster));
	memcpy(cluster, table, strlen(table) - strlen(fsname));
	fsname++;

	flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL;

	/*
	 * create/join lockspace
	 */

	error = dlm_new_lockspace(fsname, cluster, flags, GDLM_LVB_SIZE,
				  &gdlm_lockspace_ops, sdp, &ops_result,
				  &ls->ls_dlm);
	if (error) {
		fs_err(sdp, "dlm_new_lockspace error %d\n", error);
		goto fail_free;
	}

	if (ops_result < 0) {
		/*
		 * dlm does not support ops callbacks,
		 * old dlm_controld/gfs_controld are used, try without ops.
		 */
		fs_info(sdp, "dlm lockspace ops not used\n");
		free_recover_size(ls);
		set_bit(DFL_NO_DLM_OPS, &ls->ls_recover_flags);
		return 0;
	}

	if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags)) {
		fs_err(sdp, "dlm lockspace ops disallow jid preset\n");
		error = -EINVAL;
		goto fail_release;
	}

	/*
	 * control_mount() uses control_lock to determine first mounter,
	 * and for later mounts, waits for any recoveries to be cleared.
	 */

	error = control_mount(sdp);
	if (error) {
		fs_err(sdp, "mount control error %d\n", error);
		goto fail_release;
	}

	ls->ls_first = !!test_bit(DFL_FIRST_MOUNT, &ls->ls_recover_flags);
	clear_bit(SDF_NOJOURNALID, &sdp->sd_flags);
	smp_mb__after_atomic();
	wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
	return 0;

fail_release:
	dlm_release_lockspace(ls->ls_dlm, 2);
fail_free:
	free_recover_size(ls);
fail:
	return error;
}