Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ocfs2: POSIX file locks support

This is actually pretty easy since fs/dlm already handles the bulk of the
work. The Ocfs2 userspace cluster stack module already uses fs/dlm as the
underlying lock manager, so I only had to add the right calls.

Cluster-aware POSIX locks ("plocks") can be turned off by the same means at
UNIX locks - mount with 'noflocks', or create a local-only Ocfs2 volume.
Internally, the file system uses two sets of file_operations, depending on
whether cluster aware plocks is required. This turns out to be easier than
implementing local-only versions of ->lock.

Signed-off-by: Mark Fasheh <mfasheh@suse.com>

+155 -3
+52 -1
fs/ocfs2/file.c
··· 2237 2237 .permission = ocfs2_permission, 2238 2238 }; 2239 2239 2240 + /* 2241 + * Other than ->lock, keep ocfs2_fops and ocfs2_dops in sync with 2242 + * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks! 2243 + */ 2240 2244 const struct file_operations ocfs2_fops = { 2245 + .llseek = generic_file_llseek, 2246 + .read = do_sync_read, 2247 + .write = do_sync_write, 2248 + .mmap = ocfs2_mmap, 2249 + .fsync = ocfs2_sync_file, 2250 + .release = ocfs2_file_release, 2251 + .open = ocfs2_file_open, 2252 + .aio_read = ocfs2_file_aio_read, 2253 + .aio_write = ocfs2_file_aio_write, 2254 + .unlocked_ioctl = ocfs2_ioctl, 2255 + #ifdef CONFIG_COMPAT 2256 + .compat_ioctl = ocfs2_compat_ioctl, 2257 + #endif 2258 + .lock = ocfs2_lock, 2259 + .flock = ocfs2_flock, 2260 + .splice_read = ocfs2_file_splice_read, 2261 + .splice_write = ocfs2_file_splice_write, 2262 + }; 2263 + 2264 + const struct file_operations ocfs2_dops = { 2265 + .llseek = generic_file_llseek, 2266 + .read = generic_read_dir, 2267 + .readdir = ocfs2_readdir, 2268 + .fsync = ocfs2_sync_file, 2269 + .release = ocfs2_dir_release, 2270 + .open = ocfs2_dir_open, 2271 + .unlocked_ioctl = ocfs2_ioctl, 2272 + #ifdef CONFIG_COMPAT 2273 + .compat_ioctl = ocfs2_compat_ioctl, 2274 + #endif 2275 + .lock = ocfs2_lock, 2276 + .flock = ocfs2_flock, 2277 + }; 2278 + 2279 + /* 2280 + * POSIX-lockless variants of our file_operations. 2281 + * 2282 + * These will be used if the underlying cluster stack does not support 2283 + * posix file locking, if the user passes the "localflocks" mount 2284 + * option, or if we have a local-only fs. 2285 + * 2286 + * ocfs2_flock is in here because all stacks handle UNIX file locks, 2287 + * so we still want it in the case of no stack support for 2288 + * plocks. Internally, it will do the right thing when asked to ignore 2289 + * the cluster. 2290 + */ 2291 + const struct file_operations ocfs2_fops_no_plocks = { 2241 2292 .llseek = generic_file_llseek, 2242 2293 .read = do_sync_read, 2243 2294 .write = do_sync_write, ··· 2307 2256 .splice_write = ocfs2_file_splice_write, 2308 2257 }; 2309 2258 2310 - const struct file_operations ocfs2_dops = { 2259 + const struct file_operations ocfs2_dops_no_plocks = { 2311 2260 .llseek = generic_file_llseek, 2312 2261 .read = generic_read_dir, 2313 2262 .readdir = ocfs2_readdir,
+2
fs/ocfs2/file.h
··· 28 28 29 29 extern const struct file_operations ocfs2_fops; 30 30 extern const struct file_operations ocfs2_dops; 31 + extern const struct file_operations ocfs2_fops_no_plocks; 32 + extern const struct file_operations ocfs2_dops_no_plocks; 31 33 extern const struct inode_operations ocfs2_file_iops; 32 34 extern const struct inode_operations ocfs2_special_file_iops; 33 35 struct ocfs2_alloc_context;
+13 -2
fs/ocfs2/inode.c
··· 219 219 struct super_block *sb; 220 220 struct ocfs2_super *osb; 221 221 int status = -EINVAL; 222 + int use_plocks = 1; 222 223 223 224 mlog_entry("(0x%p, size:%llu)\n", inode, 224 225 (unsigned long long)le64_to_cpu(fe->i_size)); 225 226 226 227 sb = inode->i_sb; 227 228 osb = OCFS2_SB(sb); 229 + 230 + if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) || 231 + ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks()) 232 + use_plocks = 0; 228 233 229 234 /* this means that read_inode cannot create a superblock inode 230 235 * today. change if needed. */ ··· 300 295 301 296 switch (inode->i_mode & S_IFMT) { 302 297 case S_IFREG: 303 - inode->i_fop = &ocfs2_fops; 298 + if (use_plocks) 299 + inode->i_fop = &ocfs2_fops; 300 + else 301 + inode->i_fop = &ocfs2_fops_no_plocks; 304 302 inode->i_op = &ocfs2_file_iops; 305 303 i_size_write(inode, le64_to_cpu(fe->i_size)); 306 304 break; 307 305 case S_IFDIR: 308 306 inode->i_op = &ocfs2_dir_iops; 309 - inode->i_fop = &ocfs2_dops; 307 + if (use_plocks) 308 + inode->i_fop = &ocfs2_dops; 309 + else 310 + inode->i_fop = &ocfs2_dops_no_plocks; 310 311 i_size_write(inode, le64_to_cpu(fe->i_size)); 311 312 break; 312 313 case S_IFLNK:
+15
fs/ocfs2/locks.c
··· 24 24 */ 25 25 26 26 #include <linux/fs.h> 27 + #include <linux/fcntl.h> 27 28 28 29 #define MLOG_MASK_PREFIX ML_INODE 29 30 #include <cluster/masklog.h> ··· 33 32 34 33 #include "dlmglue.h" 35 34 #include "file.h" 35 + #include "inode.h" 36 36 #include "locks.h" 37 37 38 38 static int ocfs2_do_flock(struct file *file, struct inode *inode, ··· 124 122 return ocfs2_do_funlock(file, cmd, fl); 125 123 else 126 124 return ocfs2_do_flock(file, inode, cmd, fl); 125 + } 126 + 127 + int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl) 128 + { 129 + struct inode *inode = file->f_mapping->host; 130 + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); 131 + 132 + if (!(fl->fl_flags & FL_POSIX)) 133 + return -ENOLCK; 134 + if (__mandatory_lock(inode)) 135 + return -ENOLCK; 136 + 137 + return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl); 127 138 }
+1
fs/ocfs2/locks.h
··· 27 27 #define OCFS2_LOCKS_H 28 28 29 29 int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl); 30 + int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl); 30 31 31 32 #endif /* OCFS2_LOCKS_H */
+33
fs/ocfs2/stack_user.c
··· 28 28 #include "ocfs2.h" /* For struct ocfs2_lock_res */ 29 29 #include "stackglue.h" 30 30 31 + #include <linux/dlm_plock.h> 31 32 32 33 /* 33 34 * The control protocol starts with a handshake. Until the handshake ··· 747 746 { 748 747 } 749 748 749 + static int user_plock(struct ocfs2_cluster_connection *conn, 750 + u64 ino, 751 + struct file *file, 752 + int cmd, 753 + struct file_lock *fl) 754 + { 755 + /* 756 + * This more or less just demuxes the plock request into any 757 + * one of three dlm calls. 758 + * 759 + * Internally, fs/dlm will pass these to a misc device, which 760 + * a userspace daemon will read and write to. 761 + * 762 + * For now, cancel requests (which happen internally only), 763 + * are turned into unlocks. Most of this function taken from 764 + * gfs2_lock. 765 + */ 766 + 767 + if (cmd == F_CANCELLK) { 768 + cmd = F_SETLK; 769 + fl->fl_type = F_UNLCK; 770 + } 771 + 772 + if (IS_GETLK(cmd)) 773 + return dlm_posix_get(conn->cc_lockspace, ino, file, fl); 774 + else if (fl->fl_type == F_UNLCK) 775 + return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl); 776 + else 777 + return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl); 778 + } 779 + 750 780 /* 751 781 * Compare a requested locking protocol version against the current one. 752 782 * ··· 871 839 .dlm_unlock = user_dlm_unlock, 872 840 .lock_status = user_dlm_lock_status, 873 841 .lock_lvb = user_dlm_lvb, 842 + .plock = user_plock, 874 843 .dump_lksb = user_dlm_dump_lksb, 875 844 }; 876 845
+20
fs/ocfs2/stackglue.c
··· 288 288 } 289 289 EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); 290 290 291 + int ocfs2_stack_supports_plocks(void) 292 + { 293 + return !!(active_stack && active_stack->sp_ops->plock); 294 + } 295 + EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks); 296 + 297 + /* 298 + * ocfs2_plock() can only be safely called if 299 + * ocfs2_stack_supports_plocks() returned true 300 + */ 301 + int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, 302 + struct file *file, int cmd, struct file_lock *fl) 303 + { 304 + WARN_ON_ONCE(active_stack->sp_ops->plock == NULL); 305 + if (active_stack->sp_ops->plock) 306 + return active_stack->sp_ops->plock(conn, ino, file, cmd, fl); 307 + return -EOPNOTSUPP; 308 + } 309 + EXPORT_SYMBOL_GPL(ocfs2_plock); 310 + 291 311 int ocfs2_cluster_connect(const char *stack_name, 292 312 const char *group, 293 313 int grouplen,
+19
fs/ocfs2/stackglue.h
··· 28 28 #include "dlm/dlmapi.h" 29 29 #include <linux/dlm.h> 30 30 31 + /* Needed for plock-related prototypes */ 32 + struct file; 33 + struct file_lock; 34 + 31 35 /* 32 36 * dlmconstants.h does not have a LOCAL flag. We hope to remove it 33 37 * some day, but right now we need it. Let's fake it. This value is larger ··· 191 187 void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); 192 188 193 189 /* 190 + * Cluster-aware posix locks 191 + * 192 + * This is NULL for stacks which do not support posix locks. 193 + */ 194 + int (*plock)(struct ocfs2_cluster_connection *conn, 195 + u64 ino, 196 + struct file *file, 197 + int cmd, 198 + struct file_lock *fl); 199 + 200 + /* 194 201 * This is an optoinal debugging hook. If provided, the 195 202 * stack can dump debugging information about this lock. 196 203 */ ··· 254 239 int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); 255 240 void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); 256 241 void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); 242 + 243 + int ocfs2_stack_supports_plocks(void); 244 + int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, 245 + struct file *file, int cmd, struct file_lock *fl); 257 246 258 247 void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto); 259 248