forked from Minki/linux
328970de0e
Based on 1 normalized pattern(s): 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 84 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190524100844.756442981@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
131 lines
2.8 KiB
C
131 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* -*- 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.
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/fcntl.h>
|
|
|
|
#include <cluster/masklog.h>
|
|
|
|
#include "ocfs2.h"
|
|
|
|
#include "dlmglue.h"
|
|
#include "file.h"
|
|
#include "inode.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;
|
|
struct file_lock request;
|
|
|
|
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.
|
|
*/
|
|
|
|
locks_init_lock(&request);
|
|
request.fl_type = F_UNLCK;
|
|
request.fl_flags = FL_FLOCK;
|
|
locks_lock_file_wait(file, &request);
|
|
|
|
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 = locks_lock_file_wait(file, fl);
|
|
if (ret)
|
|
ocfs2_file_unlock(file);
|
|
|
|
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 = locks_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 locks_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);
|
|
}
|
|
|
|
int ocfs2_lock(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_POSIX))
|
|
return -ENOLCK;
|
|
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
|
|
return -ENOLCK;
|
|
|
|
return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
|
|
}
|