153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh/* -*- mode: c; c-basic-offset: 8; -*-
253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * vim: noexpandtab sw=8 ts=8 sts=0:
353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh *
453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * locks.c
553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh *
653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * Userspace file locking support
753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh *
853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * Copyright (C) 2007 Oracle.  All rights reserved.
953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh *
1053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * This program is free software; you can redistribute it and/or
1153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * modify it under the terms of the GNU General Public
1253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * License as published by the Free Software Foundation; either
1353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * version 2 of the License, or (at your option) any later version.
1453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh *
1553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * This program is distributed in the hope that it will be useful,
1653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * but WITHOUT ANY WARRANTY; without even the implied warranty of
1753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * General Public License for more details.
1953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh *
2053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * You should have received a copy of the GNU General Public
2153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * License along with this program; if not, write to the
2253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
2353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * Boston, MA 021110-1307, USA.
2453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh */
2553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
2653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh#include <linux/fs.h>
2753da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh#include <linux/fcntl.h>
2853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
2953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh#include <cluster/masklog.h>
3053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
3153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh#include "ocfs2.h"
3253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
3353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh#include "dlmglue.h"
3453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh#include "file.h"
3553da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh#include "inode.h"
3653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh#include "locks.h"
3753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
3853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fashehstatic int ocfs2_do_flock(struct file *file, struct inode *inode,
3953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh			  int cmd, struct file_lock *fl)
4053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh{
4153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	int ret = 0, level = 0, trylock = 0;
4253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	struct ocfs2_file_private *fp = file->private_data;
4353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	struct ocfs2_lock_res *lockres = &fp->fp_flock;
4453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
4553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (fl->fl_type == F_WRLCK)
4653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		level = 1;
4753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (!IS_SETLKW(cmd))
4853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		trylock = 1;
4953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
5053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	mutex_lock(&fp->fp_mutex);
5153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
5253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
5353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	    lockres->l_level > LKM_NLMODE) {
5453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		int old_level = 0;
5553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
5653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		if (lockres->l_level == LKM_EXMODE)
5753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh			old_level = 1;
5853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
5953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		if (level == old_level)
6053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh			goto out;
6153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
6253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		/*
6353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		 * Converting an existing lock is not guaranteed to be
6453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		 * atomic, so we can get away with simply unlocking
6553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		 * here and allowing the lock code to try at the new
6653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		 * level.
6753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		 */
6853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
6953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		flock_lock_file_wait(file,
7053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh				     &(struct file_lock){.fl_type = F_UNLCK});
7153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
7253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		ocfs2_file_unlock(file);
7353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	}
7453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
7553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	ret = ocfs2_file_lock(file, level, trylock);
7653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (ret) {
7753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		if (ret == -EAGAIN && trylock)
7853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh			ret = -EWOULDBLOCK;
7953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		else
8053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh			mlog_errno(ret);
8153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		goto out;
8253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	}
8353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
8453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	ret = flock_lock_file_wait(file, fl);
85e228f6439862359f9b26f9d62634e4fce180b54aWengang Wang	if (ret)
86e228f6439862359f9b26f9d62634e4fce180b54aWengang Wang		ocfs2_file_unlock(file);
8753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
8853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fashehout:
8953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	mutex_unlock(&fp->fp_mutex);
9053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
9153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	return ret;
9253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh}
9353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
9453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fashehstatic int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
9553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh{
9653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	int ret;
9753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	struct ocfs2_file_private *fp = file->private_data;
9853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
9953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	mutex_lock(&fp->fp_mutex);
10053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	ocfs2_file_unlock(file);
10153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	ret = flock_lock_file_wait(file, fl);
10253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	mutex_unlock(&fp->fp_mutex);
10353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
10453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	return ret;
10553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh}
10653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
10753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh/*
10853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
10953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh */
11053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fashehint ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
11153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh{
11253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	struct inode *inode = file->f_mapping->host;
11353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
11453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
11553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (!(fl->fl_flags & FL_FLOCK))
11653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		return -ENOLCK;
11753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (__mandatory_lock(inode))
11853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		return -ENOLCK;
11953fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
12053fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
12153fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	    ocfs2_mount_local(osb))
12253fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		return flock_lock_file_wait(file, fl);
12353fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh
12453fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	if (fl->fl_type == F_UNLCK)
12553fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		return ocfs2_do_funlock(file, cmd, fl);
12653fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh	else
12753fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh		return ocfs2_do_flock(file, inode, cmd, fl);
12853fc622b9e829c8e632e45ef8c14f054388759c1Mark Fasheh}
12953da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh
13053da4939f349d4edd283b043219221ca5b78e4d4Mark Fashehint ocfs2_lock(struct file *file, int cmd, struct file_lock *fl)
13153da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh{
13253da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh	struct inode *inode = file->f_mapping->host;
13353da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
13453da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh
13553da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh	if (!(fl->fl_flags & FL_POSIX))
13653da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh		return -ENOLCK;
137ee860b6a650360c91f5d5f9a94262aad9be90015Sachin Prabhu	if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
13853da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh		return -ENOLCK;
13953da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh
14053da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh	return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
14153da4939f349d4edd283b043219221ca5b78e4d4Mark Fasheh}
142