diff options
author | Mark Fasheh <mfasheh@suse.com> | 2008-07-21 17:29:16 -0400 |
---|---|---|
committer | Mark Fasheh <mfasheh@suse.com> | 2008-10-13 16:57:57 -0400 |
commit | 53da4939f349d4edd283b043219221ca5b78e4d4 (patch) | |
tree | 3e0f8e1bd5474822431cffd1e449df9b639e1772 | |
parent | a447c0932445f92ce6f4c1bd020f62c5097a7842 (diff) |
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>
-rw-r--r-- | fs/ocfs2/file.c | 51 | ||||
-rw-r--r-- | fs/ocfs2/file.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/inode.c | 15 | ||||
-rw-r--r-- | fs/ocfs2/locks.c | 15 | ||||
-rw-r--r-- | fs/ocfs2/locks.h | 1 | ||||
-rw-r--r-- | fs/ocfs2/stack_user.c | 33 | ||||
-rw-r--r-- | fs/ocfs2/stackglue.c | 20 | ||||
-rw-r--r-- | fs/ocfs2/stackglue.h | 19 |
8 files changed, 154 insertions, 2 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index ed38796052d2..1015ef16a8bf 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2237,6 +2237,10 @@ const struct inode_operations ocfs2_special_file_iops = { | |||
2237 | .permission = ocfs2_permission, | 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 | const struct file_operations ocfs2_fops = { | 2244 | const struct file_operations ocfs2_fops = { |
2241 | .llseek = generic_file_llseek, | 2245 | .llseek = generic_file_llseek, |
2242 | .read = do_sync_read, | 2246 | .read = do_sync_read, |
@@ -2251,6 +2255,7 @@ const struct file_operations ocfs2_fops = { | |||
2251 | #ifdef CONFIG_COMPAT | 2255 | #ifdef CONFIG_COMPAT |
2252 | .compat_ioctl = ocfs2_compat_ioctl, | 2256 | .compat_ioctl = ocfs2_compat_ioctl, |
2253 | #endif | 2257 | #endif |
2258 | .lock = ocfs2_lock, | ||
2254 | .flock = ocfs2_flock, | 2259 | .flock = ocfs2_flock, |
2255 | .splice_read = ocfs2_file_splice_read, | 2260 | .splice_read = ocfs2_file_splice_read, |
2256 | .splice_write = ocfs2_file_splice_write, | 2261 | .splice_write = ocfs2_file_splice_write, |
@@ -2267,5 +2272,51 @@ const struct file_operations ocfs2_dops = { | |||
2267 | #ifdef CONFIG_COMPAT | 2272 | #ifdef CONFIG_COMPAT |
2268 | .compat_ioctl = ocfs2_compat_ioctl, | 2273 | .compat_ioctl = ocfs2_compat_ioctl, |
2269 | #endif | 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 = { | ||
2292 | .llseek = generic_file_llseek, | ||
2293 | .read = do_sync_read, | ||
2294 | .write = do_sync_write, | ||
2295 | .mmap = ocfs2_mmap, | ||
2296 | .fsync = ocfs2_sync_file, | ||
2297 | .release = ocfs2_file_release, | ||
2298 | .open = ocfs2_file_open, | ||
2299 | .aio_read = ocfs2_file_aio_read, | ||
2300 | .aio_write = ocfs2_file_aio_write, | ||
2301 | .unlocked_ioctl = ocfs2_ioctl, | ||
2302 | #ifdef CONFIG_COMPAT | ||
2303 | .compat_ioctl = ocfs2_compat_ioctl, | ||
2304 | #endif | ||
2305 | .flock = ocfs2_flock, | ||
2306 | .splice_read = ocfs2_file_splice_read, | ||
2307 | .splice_write = ocfs2_file_splice_write, | ||
2308 | }; | ||
2309 | |||
2310 | const struct file_operations ocfs2_dops_no_plocks = { | ||
2311 | .llseek = generic_file_llseek, | ||
2312 | .read = generic_read_dir, | ||
2313 | .readdir = ocfs2_readdir, | ||
2314 | .fsync = ocfs2_sync_file, | ||
2315 | .release = ocfs2_dir_release, | ||
2316 | .open = ocfs2_dir_open, | ||
2317 | .unlocked_ioctl = ocfs2_ioctl, | ||
2318 | #ifdef CONFIG_COMPAT | ||
2319 | .compat_ioctl = ocfs2_compat_ioctl, | ||
2320 | #endif | ||
2270 | .flock = ocfs2_flock, | 2321 | .flock = ocfs2_flock, |
2271 | }; | 2322 | }; |
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 1e27b4d017ea..5a6d3e48e4ba 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h | |||
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | extern const struct file_operations ocfs2_fops; | 29 | extern const struct file_operations ocfs2_fops; |
30 | extern const struct file_operations ocfs2_dops; | 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 | extern const struct inode_operations ocfs2_file_iops; | 33 | extern const struct inode_operations ocfs2_file_iops; |
32 | extern const struct inode_operations ocfs2_special_file_iops; | 34 | extern const struct inode_operations ocfs2_special_file_iops; |
33 | struct ocfs2_alloc_context; | 35 | struct ocfs2_alloc_context; |
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 7e9e4c79aec7..99f012a0f207 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -219,6 +219,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, | |||
219 | struct super_block *sb; | 219 | struct super_block *sb; |
220 | struct ocfs2_super *osb; | 220 | struct ocfs2_super *osb; |
221 | int status = -EINVAL; | 221 | int status = -EINVAL; |
222 | int use_plocks = 1; | ||
222 | 223 | ||
223 | mlog_entry("(0x%p, size:%llu)\n", inode, | 224 | mlog_entry("(0x%p, size:%llu)\n", inode, |
224 | (unsigned long long)le64_to_cpu(fe->i_size)); | 225 | (unsigned long long)le64_to_cpu(fe->i_size)); |
@@ -226,6 +227,10 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, | |||
226 | sb = inode->i_sb; | 227 | sb = inode->i_sb; |
227 | osb = OCFS2_SB(sb); | 228 | osb = OCFS2_SB(sb); |
228 | 229 | ||
230 | if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) || | ||
231 | ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks()) | ||
232 | use_plocks = 0; | ||
233 | |||
229 | /* this means that read_inode cannot create a superblock inode | 234 | /* this means that read_inode cannot create a superblock inode |
230 | * today. change if needed. */ | 235 | * today. change if needed. */ |
231 | if (!OCFS2_IS_VALID_DINODE(fe) || | 236 | if (!OCFS2_IS_VALID_DINODE(fe) || |
@@ -295,13 +300,19 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, | |||
295 | 300 | ||
296 | switch (inode->i_mode & S_IFMT) { | 301 | switch (inode->i_mode & S_IFMT) { |
297 | case S_IFREG: | 302 | case S_IFREG: |
298 | inode->i_fop = &ocfs2_fops; | 303 | if (use_plocks) |
304 | inode->i_fop = &ocfs2_fops; | ||
305 | else | ||
306 | inode->i_fop = &ocfs2_fops_no_plocks; | ||
299 | inode->i_op = &ocfs2_file_iops; | 307 | inode->i_op = &ocfs2_file_iops; |
300 | i_size_write(inode, le64_to_cpu(fe->i_size)); | 308 | i_size_write(inode, le64_to_cpu(fe->i_size)); |
301 | break; | 309 | break; |
302 | case S_IFDIR: | 310 | case S_IFDIR: |
303 | inode->i_op = &ocfs2_dir_iops; | 311 | inode->i_op = &ocfs2_dir_iops; |
304 | inode->i_fop = &ocfs2_dops; | 312 | if (use_plocks) |
313 | inode->i_fop = &ocfs2_dops; | ||
314 | else | ||
315 | inode->i_fop = &ocfs2_dops_no_plocks; | ||
305 | i_size_write(inode, le64_to_cpu(fe->i_size)); | 316 | i_size_write(inode, le64_to_cpu(fe->i_size)); |
306 | break; | 317 | break; |
307 | case S_IFLNK: | 318 | case S_IFLNK: |
diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c index 203f87143877..544ac6245175 100644 --- a/fs/ocfs2/locks.c +++ b/fs/ocfs2/locks.c | |||
@@ -24,6 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
27 | #include <linux/fcntl.h> | ||
27 | 28 | ||
28 | #define MLOG_MASK_PREFIX ML_INODE | 29 | #define MLOG_MASK_PREFIX ML_INODE |
29 | #include <cluster/masklog.h> | 30 | #include <cluster/masklog.h> |
@@ -32,6 +33,7 @@ | |||
32 | 33 | ||
33 | #include "dlmglue.h" | 34 | #include "dlmglue.h" |
34 | #include "file.h" | 35 | #include "file.h" |
36 | #include "inode.h" | ||
35 | #include "locks.h" | 37 | #include "locks.h" |
36 | 38 | ||
37 | static int ocfs2_do_flock(struct file *file, struct inode *inode, | 39 | static int ocfs2_do_flock(struct file *file, struct inode *inode, |
@@ -123,3 +125,16 @@ int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl) | |||
123 | else | 125 | else |
124 | return ocfs2_do_flock(file, inode, cmd, fl); | 126 | return ocfs2_do_flock(file, inode, cmd, fl); |
125 | } | 127 | } |
128 | |||
129 | int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl) | ||
130 | { | ||
131 | struct inode *inode = file->f_mapping->host; | ||
132 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | ||
133 | |||
134 | if (!(fl->fl_flags & FL_POSIX)) | ||
135 | return -ENOLCK; | ||
136 | if (__mandatory_lock(inode)) | ||
137 | return -ENOLCK; | ||
138 | |||
139 | return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl); | ||
140 | } | ||
diff --git a/fs/ocfs2/locks.h b/fs/ocfs2/locks.h index 9743ef2324ec..496d488b271f 100644 --- a/fs/ocfs2/locks.h +++ b/fs/ocfs2/locks.h | |||
@@ -27,5 +27,6 @@ | |||
27 | #define OCFS2_LOCKS_H | 27 | #define OCFS2_LOCKS_H |
28 | 28 | ||
29 | int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl); | 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 | #endif /* OCFS2_LOCKS_H */ | 32 | #endif /* OCFS2_LOCKS_H */ |
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c index 353fc35c6748..faec2d879357 100644 --- a/fs/ocfs2/stack_user.c +++ b/fs/ocfs2/stack_user.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "ocfs2.h" /* For struct ocfs2_lock_res */ | 28 | #include "ocfs2.h" /* For struct ocfs2_lock_res */ |
29 | #include "stackglue.h" | 29 | #include "stackglue.h" |
30 | 30 | ||
31 | #include <linux/dlm_plock.h> | ||
31 | 32 | ||
32 | /* | 33 | /* |
33 | * The control protocol starts with a handshake. Until the handshake | 34 | * The control protocol starts with a handshake. Until the handshake |
@@ -746,6 +747,37 @@ static void user_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb) | |||
746 | { | 747 | { |
747 | } | 748 | } |
748 | 749 | ||
750 | static int user_plock(struct ocfs2_cluster_connection *conn, | ||
751 | u64 ino, | ||
752 | struct file *file, | ||
753 | int cmd, | ||
754 | struct file_lock *fl) | ||
755 | { | ||
756 | /* | ||
757 | * This more or less just demuxes the plock request into any | ||
758 | * one of three dlm calls. | ||
759 | * | ||
760 | * Internally, fs/dlm will pass these to a misc device, which | ||
761 | * a userspace daemon will read and write to. | ||
762 | * | ||
763 | * For now, cancel requests (which happen internally only), | ||
764 | * are turned into unlocks. Most of this function taken from | ||
765 | * gfs2_lock. | ||
766 | */ | ||
767 | |||
768 | if (cmd == F_CANCELLK) { | ||
769 | cmd = F_SETLK; | ||
770 | fl->fl_type = F_UNLCK; | ||
771 | } | ||
772 | |||
773 | if (IS_GETLK(cmd)) | ||
774 | return dlm_posix_get(conn->cc_lockspace, ino, file, fl); | ||
775 | else if (fl->fl_type == F_UNLCK) | ||
776 | return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl); | ||
777 | else | ||
778 | return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl); | ||
779 | } | ||
780 | |||
749 | /* | 781 | /* |
750 | * Compare a requested locking protocol version against the current one. | 782 | * Compare a requested locking protocol version against the current one. |
751 | * | 783 | * |
@@ -839,6 +871,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = { | |||
839 | .dlm_unlock = user_dlm_unlock, | 871 | .dlm_unlock = user_dlm_unlock, |
840 | .lock_status = user_dlm_lock_status, | 872 | .lock_status = user_dlm_lock_status, |
841 | .lock_lvb = user_dlm_lvb, | 873 | .lock_lvb = user_dlm_lvb, |
874 | .plock = user_plock, | ||
842 | .dump_lksb = user_dlm_dump_lksb, | 875 | .dump_lksb = user_dlm_dump_lksb, |
843 | }; | 876 | }; |
844 | 877 | ||
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c index 07f348b8d721..7150f5dce957 100644 --- a/fs/ocfs2/stackglue.c +++ b/fs/ocfs2/stackglue.c | |||
@@ -288,6 +288,26 @@ void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb) | |||
288 | } | 288 | } |
289 | EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); | 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 | int ocfs2_cluster_connect(const char *stack_name, | 311 | int ocfs2_cluster_connect(const char *stack_name, |
292 | const char *group, | 312 | const char *group, |
293 | int grouplen, | 313 | int grouplen, |
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h index db56281dd1be..c571af375ef8 100644 --- a/fs/ocfs2/stackglue.h +++ b/fs/ocfs2/stackglue.h | |||
@@ -28,6 +28,10 @@ | |||
28 | #include "dlm/dlmapi.h" | 28 | #include "dlm/dlmapi.h" |
29 | #include <linux/dlm.h> | 29 | #include <linux/dlm.h> |
30 | 30 | ||
31 | /* Needed for plock-related prototypes */ | ||
32 | struct file; | ||
33 | struct file_lock; | ||
34 | |||
31 | /* | 35 | /* |
32 | * dlmconstants.h does not have a LOCAL flag. We hope to remove it | 36 | * dlmconstants.h does not have a LOCAL flag. We hope to remove it |
33 | * some day, but right now we need it. Let's fake it. This value is larger | 37 | * some day, but right now we need it. Let's fake it. This value is larger |
@@ -187,6 +191,17 @@ struct ocfs2_stack_operations { | |||
187 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); | 191 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); |
188 | 192 | ||
189 | /* | 193 | /* |
194 | * Cluster-aware posix locks | ||
195 | * | ||
196 | * This is NULL for stacks which do not support posix locks. | ||
197 | */ | ||
198 | int (*plock)(struct ocfs2_cluster_connection *conn, | ||
199 | u64 ino, | ||
200 | struct file *file, | ||
201 | int cmd, | ||
202 | struct file_lock *fl); | ||
203 | |||
204 | /* | ||
190 | * This is an optoinal debugging hook. If provided, the | 205 | * This is an optoinal debugging hook. If provided, the |
191 | * stack can dump debugging information about this lock. | 206 | * stack can dump debugging information about this lock. |
192 | */ | 207 | */ |
@@ -240,6 +255,10 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb); | |||
240 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); | 255 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); |
241 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); | 256 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); |
242 | 257 | ||
258 | int ocfs2_stack_supports_plocks(void); | ||
259 | int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, | ||
260 | struct file *file, int cmd, struct file_lock *fl); | ||
261 | |||
243 | void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto); | 262 | void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto); |
244 | 263 | ||
245 | 264 | ||