2019-05-24 13:04:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2021-05-07 04:06:44 +03:00
/*
2007-12-21 03:49:04 +03:00
* locks . c
*
* Userspace file locking support
*
* Copyright ( C ) 2007 Oracle . All rights reserved .
*/
# include <linux/fs.h>
2022-11-20 17:15:34 +03:00
# include <linux/filelock.h>
2008-07-22 01:29:16 +04:00
# include <linux/fcntl.h>
2007-12-21 03:49:04 +03:00
# include <cluster/masklog.h>
# include "ocfs2.h"
# include "dlmglue.h"
# include "file.h"
2008-07-22 01:29:16 +04:00
# include "inode.h"
2007-12-21 03:49:04 +03:00
# 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 ;
2018-11-30 02:04:08 +03:00
struct file_lock request ;
2007-12-21 03:49:04 +03:00
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 .
*/
2018-11-30 02:04:08 +03:00
locks_init_lock ( & request ) ;
request . fl_type = F_UNLCK ;
request . fl_flags = FL_FLOCK ;
locks_lock_file_wait ( file , & request ) ;
2007-12-21 03:49:04 +03:00
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 ;
}
2015-10-22 20:38:14 +03:00
ret = locks_lock_file_wait ( file , fl ) ;
2014-04-04 01:47:09 +04:00
if ( ret )
ocfs2_file_unlock ( file ) ;
2007-12-21 03:49:04 +03:00
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 ) ;
2015-10-22 20:38:14 +03:00
ret = locks_lock_file_wait ( file , fl ) ;
2007-12-21 03:49:04 +03:00
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 ( ( osb - > s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS ) | |
ocfs2_mount_local ( osb ) )
2015-10-22 20:38:14 +03:00
return locks_lock_file_wait ( file , fl ) ;
2007-12-21 03:49:04 +03:00
if ( fl - > fl_type = = F_UNLCK )
return ocfs2_do_funlock ( file , cmd , fl ) ;
else
return ocfs2_do_flock ( file , inode , cmd , fl ) ;
}
2008-07-22 01:29:16 +04:00
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 ;
return ocfs2_plock ( osb - > cconn , OCFS2_I ( inode ) - > ip_blkno , file , cmd , fl ) ;
}