linux/fs/ocfs2/locks.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* -*- mode: c; c-basic-offset: 8; -*-
   3 * vim: noexpandtab sw=8 ts=8 sts=0:
   4 *
   5 * locks.c
   6 *
   7 * Userspace file locking support
   8 *
   9 * Copyright (C) 2007 Oracle.  All rights reserved.
  10 */
  11
  12#include <linux/fs.h>
  13#include <linux/fcntl.h>
  14
  15#include <cluster/masklog.h>
  16
  17#include "ocfs2.h"
  18
  19#include "dlmglue.h"
  20#include "file.h"
  21#include "inode.h"
  22#include "locks.h"
  23
  24static int ocfs2_do_flock(struct file *file, struct inode *inode,
  25                          int cmd, struct file_lock *fl)
  26{
  27        int ret = 0, level = 0, trylock = 0;
  28        struct ocfs2_file_private *fp = file->private_data;
  29        struct ocfs2_lock_res *lockres = &fp->fp_flock;
  30
  31        if (fl->fl_type == F_WRLCK)
  32                level = 1;
  33        if (!IS_SETLKW(cmd))
  34                trylock = 1;
  35
  36        mutex_lock(&fp->fp_mutex);
  37
  38        if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
  39            lockres->l_level > LKM_NLMODE) {
  40                int old_level = 0;
  41                struct file_lock request;
  42
  43                if (lockres->l_level == LKM_EXMODE)
  44                        old_level = 1;
  45
  46                if (level == old_level)
  47                        goto out;
  48
  49                /*
  50                 * Converting an existing lock is not guaranteed to be
  51                 * atomic, so we can get away with simply unlocking
  52                 * here and allowing the lock code to try at the new
  53                 * level.
  54                 */
  55
  56                locks_init_lock(&request);
  57                request.fl_type = F_UNLCK;
  58                request.fl_flags = FL_FLOCK;
  59                locks_lock_file_wait(file, &request);
  60
  61                ocfs2_file_unlock(file);
  62        }
  63
  64        ret = ocfs2_file_lock(file, level, trylock);
  65        if (ret) {
  66                if (ret == -EAGAIN && trylock)
  67                        ret = -EWOULDBLOCK;
  68                else
  69                        mlog_errno(ret);
  70                goto out;
  71        }
  72
  73        ret = locks_lock_file_wait(file, fl);
  74        if (ret)
  75                ocfs2_file_unlock(file);
  76
  77out:
  78        mutex_unlock(&fp->fp_mutex);
  79
  80        return ret;
  81}
  82
  83static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
  84{
  85        int ret;
  86        struct ocfs2_file_private *fp = file->private_data;
  87
  88        mutex_lock(&fp->fp_mutex);
  89        ocfs2_file_unlock(file);
  90        ret = locks_lock_file_wait(file, fl);
  91        mutex_unlock(&fp->fp_mutex);
  92
  93        return ret;
  94}
  95
  96/*
  97 * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
  98 */
  99int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 100{
 101        struct inode *inode = file->f_mapping->host;
 102        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 103
 104        if (!(fl->fl_flags & FL_FLOCK))
 105                return -ENOLCK;
 106        if (__mandatory_lock(inode))
 107                return -ENOLCK;
 108
 109        if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
 110            ocfs2_mount_local(osb))
 111                return locks_lock_file_wait(file, fl);
 112
 113        if (fl->fl_type == F_UNLCK)
 114                return ocfs2_do_funlock(file, cmd, fl);
 115        else
 116                return ocfs2_do_flock(file, inode, cmd, fl);
 117}
 118
 119int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl)
 120{
 121        struct inode *inode = file->f_mapping->host;
 122        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 123
 124        if (!(fl->fl_flags & FL_POSIX))
 125                return -ENOLCK;
 126        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
 127                return -ENOLCK;
 128
 129        return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
 130}
 131