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

Commit 586759f0 authored by Marc Eshel's avatar Marc Eshel Committed by J. Bruce Fields
Browse files

gfs2: nfs lock support for gfs2



Add NFS lock support to GFS2.

Signed-off-by: default avatarMarc Eshel <eshel@almaden.ibm.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
Acked-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent 1a8322b2
Loading
Loading
Loading
Loading
+99 −10
Original line number Diff line number Diff line
@@ -25,6 +25,15 @@ struct plock_op {
	struct gdlm_plock_info info;
};

struct plock_xop {
	struct plock_op xop;
	void *callback;
	void *fl;
	void *file;
	struct file_lock flc;
};


static inline void set_version(struct gdlm_plock_info *info)
{
	info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
{
	struct gdlm_ls *ls = lockspace;
	struct plock_op *op;
	struct plock_xop *xop;
	int rv;

	op = kzalloc(sizeof(*op), GFP_KERNEL);
	if (!op)
	xop = kzalloc(sizeof(*xop), GFP_KERNEL);
	if (!xop)
		return -ENOMEM;

	op = &xop->xop;
	op->info.optype		= GDLM_PLOCK_OP_LOCK;
	op->info.pid		= fl->fl_pid;
	op->info.ex		= (fl->fl_type == F_WRLCK);
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
	op->info.start		= fl->fl_start;
	op->info.end		= fl->fl_end;
	op->info.owner		= (__u64)(long) fl->fl_owner;
	if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
		xop->callback	= fl->fl_lmops->fl_grant;
		locks_init_lock(&xop->flc);
		locks_copy_lock(&xop->flc, fl);
		xop->fl		= fl;
		xop->file	= file;
	} else
		xop->callback	= NULL;

	send_op(op);

	if (xop->callback == NULL)
		wait_event(recv_wq, (op->done != 0));
	else
		return -EINPROGRESS;

	spin_lock(&ops_lock);
	if (!list_empty(&op->list)) {
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
				  (unsigned long long)name->ln_number);
	}

	kfree(op);
	kfree(xop);
	return rv;
}

/* Returns failure iff a succesful lock operation should be canceled */
static int gdlm_plock_callback(struct plock_op *op)
{
	struct file *file;
	struct file_lock *fl;
	struct file_lock *flc;
	int (*notify)(void *, void *, int) = NULL;
	struct plock_xop *xop = (struct plock_xop *)op;
	int rv = 0;

	spin_lock(&ops_lock);
	if (!list_empty(&op->list)) {
		printk(KERN_INFO "plock op on list\n");
		list_del(&op->list);
	}
	spin_unlock(&ops_lock);

	/* check if the following 2 are still valid or make a copy */
	file = xop->file;
	flc = &xop->flc;
	fl = xop->fl;
	notify = xop->callback;

	if (op->info.rv) {
		notify(flc, NULL, op->info.rv);
		goto out;
	}

	/* got fs lock; bookkeep locally as well: */
	flc->fl_flags &= ~FL_SLEEP;
	if (posix_lock_file(file, flc, NULL)) {
		/*
		 * This can only happen in the case of kmalloc() failure.
		 * The filesystem's own lock is the authoritative lock,
		 * so a failure to get the lock locally is not a disaster.
		 * As long as GFS cannot reliably cancel locks (especially
		 * in a low-memory situation), we're better off ignoring
		 * this failure than trying to recover.
		 */
		log_error("gdlm_plock: vfs lock error file %p fl %p",
				file, fl);
	}

	rv = notify(flc, NULL, 0);
	if (rv) {
		/* XXX: We need to cancel the fs lock here: */
		printk("gfs2 lock granted after lock request failed;"
						" dangling lock!\n");
		goto out;
	}

out:
	kfree(xop);
	return rv;
}

@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,

	rv = op->info.rv;

	if (rv == -ENOENT)
		rv = 0;

	kfree(op);
	return rv;
}
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
	op->info.start		= fl->fl_start;
	op->info.end		= fl->fl_end;


	send_op(op);
	wait_event(recv_wq, (op->done != 0));

@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,

	rv = op->info.rv;

	if (rv == 0)
	fl->fl_type = F_UNLCK;
	else if (rv > 0) {
	if (rv == -ENOENT)
		rv = 0;
	else if (rv == 0 && op->info.pid != fl->fl_pid) {
		fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
		fl->fl_pid = op->info.pid;
		fl->fl_start = op->info.start;
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
	}
	spin_unlock(&ops_lock);

	if (found)
		wake_up(&recv_wq);
	if (found) {
		struct plock_xop *xop;
		xop = (struct plock_xop *)op;
		if (xop->callback)
			count = gdlm_plock_callback(op);
		else
			wake_up(&recv_wq);
	} else
		printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
			(unsigned long long)info.number);
	return count;
+5 −0
Original line number Diff line number Diff line
@@ -520,6 +520,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
		}
	}

	if (cmd == F_CANCELLK) {
		/* Hack: */
		cmd = F_SETLK;
		fl->fl_type = F_UNLCK;
	}
	if (IS_GETLK(cmd))
		return gfs2_lm_plock_get(sdp, &name, file, fl);
	else if (fl->fl_type == F_UNLCK)