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

Commit 53fc622b authored by Mark Fasheh's avatar Mark Fasheh
Browse files

[PATCH 2/2] ocfs2: cluster aware flock()



Hook up ocfs2_flock(), using the new flock lock type in dlmglue.c. A new
mount option, "localflocks" is added so that users can revert to old
functionality as need be.

Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent cf8e06f1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -75,3 +75,4 @@ commit=nrsec (*) Ocfs2 can be told to sync all its data and metadata
localalloc=8(*)		Allows custom localalloc size in MB. If the value is too
			large, the fs will silently revert it to the default.
			Localalloc is not enabled for local mounts.
localflocks		This disables cluster aware flock.
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ ocfs2-objs := \
	ioctl.o 		\
	journal.o 		\
	localalloc.o 		\
	locks.o			\
	mmap.o 			\
	namei.o 		\
	resize.o		\
+59 −1
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@
#include "inode.h"
#include "ioctl.h"
#include "journal.h"
#include "locks.h"
#include "mmap.h"
#include "suballoc.h"
#include "super.h"
@@ -63,6 +64,35 @@ static int ocfs2_sync_inode(struct inode *inode)
	return sync_mapping_buffers(inode->i_mapping);
}

static int ocfs2_init_file_private(struct inode *inode, struct file *file)
{
	struct ocfs2_file_private *fp;

	fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
	if (!fp)
		return -ENOMEM;

	fp->fp_file = file;
	mutex_init(&fp->fp_mutex);
	ocfs2_file_lock_res_init(&fp->fp_flock, fp);
	file->private_data = fp;

	return 0;
}

static void ocfs2_free_file_private(struct inode *inode, struct file *file)
{
	struct ocfs2_file_private *fp = file->private_data;
	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);

	if (fp) {
		ocfs2_simple_drop_lockres(osb, &fp->fp_flock);
		ocfs2_lock_res_free(&fp->fp_flock);
		kfree(fp);
		file->private_data = NULL;
	}
}

static int ocfs2_file_open(struct inode *inode, struct file *file)
{
	int status;
@@ -89,7 +119,18 @@ static int ocfs2_file_open(struct inode *inode, struct file *file)

	oi->ip_open_count++;
	spin_unlock(&oi->ip_lock);
	status = 0;

	status = ocfs2_init_file_private(inode, file);
	if (status) {
		/*
		 * We want to set open count back if we're failing the
		 * open.
		 */
		spin_lock(&oi->ip_lock);
		oi->ip_open_count--;
		spin_unlock(&oi->ip_lock);
	}

leave:
	mlog_exit(status);
	return status;
@@ -108,11 +149,24 @@ static int ocfs2_file_release(struct inode *inode, struct file *file)
		oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
	spin_unlock(&oi->ip_lock);

	ocfs2_free_file_private(inode, file);

	mlog_exit(0);

	return 0;
}

static int ocfs2_dir_open(struct inode *inode, struct file *file)
{
	return ocfs2_init_file_private(inode, file);
}

static int ocfs2_dir_release(struct inode *inode, struct file *file)
{
	ocfs2_free_file_private(inode, file);
	return 0;
}

static int ocfs2_sync_file(struct file *file,
			   struct dentry *dentry,
			   int datasync)
@@ -2191,6 +2245,7 @@ const struct file_operations ocfs2_fops = {
#ifdef CONFIG_COMPAT
	.compat_ioctl   = ocfs2_compat_ioctl,
#endif
	.flock		= ocfs2_flock,
	.splice_read	= ocfs2_file_splice_read,
	.splice_write	= ocfs2_file_splice_write,
};
@@ -2199,8 +2254,11 @@ const struct file_operations ocfs2_dops = {
	.read		= generic_read_dir,
	.readdir	= ocfs2_readdir,
	.fsync		= ocfs2_sync_file,
	.release	= ocfs2_dir_release,
	.open		= ocfs2_dir_open,
	.ioctl		= ocfs2_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl   = ocfs2_compat_ioctl,
#endif
	.flock		= ocfs2_flock,
};

fs/ocfs2/locks.c

0 → 100644
+125 −0
Original line number Diff line number Diff line
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * locks.c
 *
 * Userspace file locking support
 *
 * Copyright (C) 2007 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/fs.h>

#define MLOG_MASK_PREFIX ML_INODE
#include <cluster/masklog.h>

#include "ocfs2.h"

#include "dlmglue.h"
#include "file.h"
#include "locks.h"

static int ocfs2_do_flock(struct file *file, struct inode *inode,
			  int cmd, struct file_lock *fl)
{
	int ret = 0, level = 0, trylock = 0;
	struct ocfs2_file_private *fp = file->private_data;
	struct ocfs2_lock_res *lockres = &fp->fp_flock;

	if (fl->fl_type == F_WRLCK)
		level = 1;
	if (!IS_SETLKW(cmd))
		trylock = 1;

	mutex_lock(&fp->fp_mutex);

	if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
	    lockres->l_level > LKM_NLMODE) {
		int old_level = 0;

		if (lockres->l_level == LKM_EXMODE)
			old_level = 1;

		if (level == old_level)
			goto out;

		/*
		 * Converting an existing lock is not guaranteed to be
		 * atomic, so we can get away with simply unlocking
		 * here and allowing the lock code to try at the new
		 * level.
		 */

		flock_lock_file_wait(file,
				     &(struct file_lock){.fl_type = F_UNLCK});

		ocfs2_file_unlock(file);
	}

	ret = ocfs2_file_lock(file, level, trylock);
	if (ret) {
		if (ret == -EAGAIN && trylock)
			ret = -EWOULDBLOCK;
		else
			mlog_errno(ret);
		goto out;
	}

	ret = flock_lock_file_wait(file, fl);

out:
	mutex_unlock(&fp->fp_mutex);

	return ret;
}

static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
{
	int ret;
	struct ocfs2_file_private *fp = file->private_data;

	mutex_lock(&fp->fp_mutex);
	ocfs2_file_unlock(file);
	ret = flock_lock_file_wait(file, fl);
	mutex_unlock(&fp->fp_mutex);

	return ret;
}

/*
 * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
 */
int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
{
	struct inode *inode = file->f_mapping->host;
	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);

	if (!(fl->fl_flags & FL_FLOCK))
		return -ENOLCK;
	if (__mandatory_lock(inode))
		return -ENOLCK;

	if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
	    ocfs2_mount_local(osb))
		return flock_lock_file_wait(file, fl);

	if (fl->fl_type == F_UNLCK)
		return ocfs2_do_funlock(file, cmd, fl);
	else
		return ocfs2_do_flock(file, inode, cmd, fl);
}

fs/ocfs2/locks.h

0 → 100644
+31 −0
Original line number Diff line number Diff line
/* -*- mode: c; c-basic-offset: 8; -*-
 * vim: noexpandtab sw=8 ts=8 sts=0:
 *
 * locks.h
 *
 * Function prototypes for Userspace file locking support
 *
 * Copyright (C) 2002, 2004 Oracle.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#ifndef OCFS2_LOCKS_H
#define OCFS2_LOCKS_H

int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);

#endif /* OCFS2_LOCKS_H */
Loading