Commit 53fc622b9e829c8e632e45ef8c14f054388759c1

Authored by Mark Fasheh
1 parent cf8e06f1a8

[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: Mark Fasheh <mark.fasheh@oracle.com>

Showing 7 changed files with 237 additions and 1 deletions Side-by-side Diff

Documentation/filesystems/ocfs2.txt
... ... @@ -75,4 +75,5 @@
75 75 localalloc=8(*) Allows custom localalloc size in MB. If the value is too
76 76 large, the fs will silently revert it to the default.
77 77 Localalloc is not enabled for local mounts.
  78 +localflocks This disables cluster aware flock.
... ... @@ -19,6 +19,7 @@
19 19 ioctl.o \
20 20 journal.o \
21 21 localalloc.o \
  22 + locks.o \
22 23 mmap.o \
23 24 namei.o \
24 25 resize.o \
... ... @@ -51,6 +51,7 @@
51 51 #include "inode.h"
52 52 #include "ioctl.h"
53 53 #include "journal.h"
  54 +#include "locks.h"
54 55 #include "mmap.h"
55 56 #include "suballoc.h"
56 57 #include "super.h"
... ... @@ -63,6 +64,35 @@
63 64 return sync_mapping_buffers(inode->i_mapping);
64 65 }
65 66  
  67 +static int ocfs2_init_file_private(struct inode *inode, struct file *file)
  68 +{
  69 + struct ocfs2_file_private *fp;
  70 +
  71 + fp = kzalloc(sizeof(struct ocfs2_file_private), GFP_KERNEL);
  72 + if (!fp)
  73 + return -ENOMEM;
  74 +
  75 + fp->fp_file = file;
  76 + mutex_init(&fp->fp_mutex);
  77 + ocfs2_file_lock_res_init(&fp->fp_flock, fp);
  78 + file->private_data = fp;
  79 +
  80 + return 0;
  81 +}
  82 +
  83 +static void ocfs2_free_file_private(struct inode *inode, struct file *file)
  84 +{
  85 + struct ocfs2_file_private *fp = file->private_data;
  86 + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  87 +
  88 + if (fp) {
  89 + ocfs2_simple_drop_lockres(osb, &fp->fp_flock);
  90 + ocfs2_lock_res_free(&fp->fp_flock);
  91 + kfree(fp);
  92 + file->private_data = NULL;
  93 + }
  94 +}
  95 +
66 96 static int ocfs2_file_open(struct inode *inode, struct file *file)
67 97 {
68 98 int status;
... ... @@ -89,7 +119,18 @@
89 119  
90 120 oi->ip_open_count++;
91 121 spin_unlock(&oi->ip_lock);
92   - status = 0;
  122 +
  123 + status = ocfs2_init_file_private(inode, file);
  124 + if (status) {
  125 + /*
  126 + * We want to set open count back if we're failing the
  127 + * open.
  128 + */
  129 + spin_lock(&oi->ip_lock);
  130 + oi->ip_open_count--;
  131 + spin_unlock(&oi->ip_lock);
  132 + }
  133 +
93 134 leave:
94 135 mlog_exit(status);
95 136 return status;
96 137  
... ... @@ -108,11 +149,24 @@
108 149 oi->ip_flags &= ~OCFS2_INODE_OPEN_DIRECT;
109 150 spin_unlock(&oi->ip_lock);
110 151  
  152 + ocfs2_free_file_private(inode, file);
  153 +
111 154 mlog_exit(0);
112 155  
113 156 return 0;
114 157 }
115 158  
  159 +static int ocfs2_dir_open(struct inode *inode, struct file *file)
  160 +{
  161 + return ocfs2_init_file_private(inode, file);
  162 +}
  163 +
  164 +static int ocfs2_dir_release(struct inode *inode, struct file *file)
  165 +{
  166 + ocfs2_free_file_private(inode, file);
  167 + return 0;
  168 +}
  169 +
116 170 static int ocfs2_sync_file(struct file *file,
117 171 struct dentry *dentry,
118 172 int datasync)
... ... @@ -2191,6 +2245,7 @@
2191 2245 #ifdef CONFIG_COMPAT
2192 2246 .compat_ioctl = ocfs2_compat_ioctl,
2193 2247 #endif
  2248 + .flock = ocfs2_flock,
2194 2249 .splice_read = ocfs2_file_splice_read,
2195 2250 .splice_write = ocfs2_file_splice_write,
2196 2251 };
2197 2252  
... ... @@ -2199,9 +2254,12 @@
2199 2254 .read = generic_read_dir,
2200 2255 .readdir = ocfs2_readdir,
2201 2256 .fsync = ocfs2_sync_file,
  2257 + .release = ocfs2_dir_release,
  2258 + .open = ocfs2_dir_open,
2202 2259 .ioctl = ocfs2_ioctl,
2203 2260 #ifdef CONFIG_COMPAT
2204 2261 .compat_ioctl = ocfs2_compat_ioctl,
2205 2262 #endif
  2263 + .flock = ocfs2_flock,
2206 2264 };
  1 +/* -*- mode: c; c-basic-offset: 8; -*-
  2 + * vim: noexpandtab sw=8 ts=8 sts=0:
  3 + *
  4 + * locks.c
  5 + *
  6 + * Userspace file locking support
  7 + *
  8 + * Copyright (C) 2007 Oracle. All rights reserved.
  9 + *
  10 + * This program is free software; you can redistribute it and/or
  11 + * modify it under the terms of the GNU General Public
  12 + * License as published by the Free Software Foundation; either
  13 + * version 2 of the License, or (at your option) any later version.
  14 + *
  15 + * This program is distributed in the hope that it will be useful,
  16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18 + * General Public License for more details.
  19 + *
  20 + * You should have received a copy of the GNU General Public
  21 + * License along with this program; if not, write to the
  22 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  23 + * Boston, MA 021110-1307, USA.
  24 + */
  25 +
  26 +#include <linux/fs.h>
  27 +
  28 +#define MLOG_MASK_PREFIX ML_INODE
  29 +#include <cluster/masklog.h>
  30 +
  31 +#include "ocfs2.h"
  32 +
  33 +#include "dlmglue.h"
  34 +#include "file.h"
  35 +#include "locks.h"
  36 +
  37 +static int ocfs2_do_flock(struct file *file, struct inode *inode,
  38 + int cmd, struct file_lock *fl)
  39 +{
  40 + int ret = 0, level = 0, trylock = 0;
  41 + struct ocfs2_file_private *fp = file->private_data;
  42 + struct ocfs2_lock_res *lockres = &fp->fp_flock;
  43 +
  44 + if (fl->fl_type == F_WRLCK)
  45 + level = 1;
  46 + if (!IS_SETLKW(cmd))
  47 + trylock = 1;
  48 +
  49 + mutex_lock(&fp->fp_mutex);
  50 +
  51 + if (lockres->l_flags & OCFS2_LOCK_ATTACHED &&
  52 + lockres->l_level > LKM_NLMODE) {
  53 + int old_level = 0;
  54 +
  55 + if (lockres->l_level == LKM_EXMODE)
  56 + old_level = 1;
  57 +
  58 + if (level == old_level)
  59 + goto out;
  60 +
  61 + /*
  62 + * Converting an existing lock is not guaranteed to be
  63 + * atomic, so we can get away with simply unlocking
  64 + * here and allowing the lock code to try at the new
  65 + * level.
  66 + */
  67 +
  68 + flock_lock_file_wait(file,
  69 + &(struct file_lock){.fl_type = F_UNLCK});
  70 +
  71 + ocfs2_file_unlock(file);
  72 + }
  73 +
  74 + ret = ocfs2_file_lock(file, level, trylock);
  75 + if (ret) {
  76 + if (ret == -EAGAIN && trylock)
  77 + ret = -EWOULDBLOCK;
  78 + else
  79 + mlog_errno(ret);
  80 + goto out;
  81 + }
  82 +
  83 + ret = flock_lock_file_wait(file, fl);
  84 +
  85 +out:
  86 + mutex_unlock(&fp->fp_mutex);
  87 +
  88 + return ret;
  89 +}
  90 +
  91 +static int ocfs2_do_funlock(struct file *file, int cmd, struct file_lock *fl)
  92 +{
  93 + int ret;
  94 + struct ocfs2_file_private *fp = file->private_data;
  95 +
  96 + mutex_lock(&fp->fp_mutex);
  97 + ocfs2_file_unlock(file);
  98 + ret = flock_lock_file_wait(file, fl);
  99 + mutex_unlock(&fp->fp_mutex);
  100 +
  101 + return ret;
  102 +}
  103 +
  104 +/*
  105 + * Overall flow of ocfs2_flock() was influenced by gfs2_flock().
  106 + */
  107 +int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
  108 +{
  109 + struct inode *inode = file->f_mapping->host;
  110 + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
  111 +
  112 + if (!(fl->fl_flags & FL_FLOCK))
  113 + return -ENOLCK;
  114 + if (__mandatory_lock(inode))
  115 + return -ENOLCK;
  116 +
  117 + if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
  118 + ocfs2_mount_local(osb))
  119 + return flock_lock_file_wait(file, fl);
  120 +
  121 + if (fl->fl_type == F_UNLCK)
  122 + return ocfs2_do_funlock(file, cmd, fl);
  123 + else
  124 + return ocfs2_do_flock(file, inode, cmd, fl);
  125 +}
  1 +/* -*- mode: c; c-basic-offset: 8; -*-
  2 + * vim: noexpandtab sw=8 ts=8 sts=0:
  3 + *
  4 + * locks.h
  5 + *
  6 + * Function prototypes for Userspace file locking support
  7 + *
  8 + * Copyright (C) 2002, 2004 Oracle. All rights reserved.
  9 + *
  10 + * This program is free software; you can redistribute it and/or
  11 + * modify it under the terms of the GNU General Public
  12 + * License as published by the Free Software Foundation; either
  13 + * version 2 of the License, or (at your option) any later version.
  14 + *
  15 + * This program is distributed in the hope that it will be useful,
  16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18 + * General Public License for more details.
  19 + *
  20 + * You should have received a copy of the GNU General Public
  21 + * License along with this program; if not, write to the
  22 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  23 + * Boston, MA 021110-1307, USA.
  24 + */
  25 +
  26 +#ifndef OCFS2_LOCKS_H
  27 +#define OCFS2_LOCKS_H
  28 +
  29 +int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
  30 +
  31 +#endif /* OCFS2_LOCKS_H */
... ... @@ -171,6 +171,7 @@
171 171 OCFS2_MOUNT_NOINTR = 1 << 2, /* Don't catch signals */
172 172 OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
173 173 OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
  174 + OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */
174 175 };
175 176  
176 177 #define OCFS2_OSB_SOFT_RO 0x0001
... ... @@ -153,6 +153,7 @@
153 153 Opt_slot,
154 154 Opt_commit,
155 155 Opt_localalloc,
  156 + Opt_localflocks,
156 157 Opt_err,
157 158 };
158 159  
... ... @@ -170,6 +171,7 @@
170 171 {Opt_slot, "preferred_slot=%u"},
171 172 {Opt_commit, "commit=%u"},
172 173 {Opt_localalloc, "localalloc=%d"},
  174 + {Opt_localflocks, "localflocks"},
173 175 {Opt_err, NULL}
174 176 };
175 177  
... ... @@ -848,6 +850,20 @@
848 850 if (option >= 0 && (option <= ocfs2_local_alloc_size(sb) * 8))
849 851 mopt->localalloc_opt = option;
850 852 break;
  853 + case Opt_localflocks:
  854 + /*
  855 + * Changing this during remount could race
  856 + * flock() requests, or "unbalance" existing
  857 + * ones (e.g., a lock is taken in one mode but
  858 + * dropped in the other). If users care enough
  859 + * to flip locking modes during remount, we
  860 + * could add a "local" flag to individual
  861 + * flock structures for proper tracking of
  862 + * state.
  863 + */
  864 + if (!is_remount)
  865 + mopt->mount_opt |= OCFS2_MOUNT_LOCALFLOCKS;
  866 + break;
851 867 default:
852 868 mlog(ML_ERROR,
853 869 "Unrecognized mount option \"%s\" "
... ... @@ -902,6 +918,9 @@
902 918  
903 919 if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
904 920 seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
  921 +
  922 + if (opts & OCFS2_MOUNT_LOCALFLOCKS)
  923 + seq_printf(s, ",localflocks,");
905 924  
906 925 return 0;
907 926 }