]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Mark Fasheh <mfasheh@suse.com> |
2 | Subject: ocfs2: POSIX file locks support | |
3 | Patch-mainline: 2.6.28? | |
4 | References: FATE110294 | |
5 | ||
6 | This is actually pretty easy since fs/dlm already handles the bulk of the | |
7 | work. The Ocfs2 userspace cluster stack module already uses fs/dlm as the | |
8 | underlying lock manager, so I only had to add the right calls. | |
9 | ||
10 | Cluster-aware POSIX locks ("plocks") can be turned off by the same means at | |
11 | UNIX locks - mount with 'noflocks', or create a local-only Ocfs2 volume. | |
12 | Internally, the file system uses two sets of file_operations, depending on | |
13 | whether cluster aware plocks is required. This turns out to be easier than | |
14 | implementing local-only versions of ->lock. | |
15 | ||
16 | Signed-off-by: Mark Fasheh <mfasheh@suse.com> | |
17 | --- | |
18 | fs/ocfs2/file.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ | |
19 | fs/ocfs2/file.h | 2 + | |
20 | fs/ocfs2/inode.c | 15 ++++++++++++-- | |
21 | fs/ocfs2/locks.c | 15 ++++++++++++++ | |
22 | fs/ocfs2/locks.h | 1 | |
23 | fs/ocfs2/stack_user.c | 33 ++++++++++++++++++++++++++++++++ | |
24 | fs/ocfs2/stackglue.c | 20 +++++++++++++++++++ | |
25 | fs/ocfs2/stackglue.h | 19 ++++++++++++++++++ | |
26 | 8 files changed, 154 insertions(+), 2 deletions(-) | |
27 | ||
28 | --- a/fs/ocfs2/file.c | |
29 | +++ b/fs/ocfs2/file.c | |
30 | @@ -2152,6 +2152,10 @@ const struct inode_operations ocfs2_spec | |
31 | .permission = ocfs2_permission, | |
32 | }; | |
33 | ||
34 | +/* | |
35 | + * Other than ->lock, keep ocfs2_fops and ocfs2_dops in sync with | |
36 | + * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks! | |
37 | + */ | |
38 | const struct file_operations ocfs2_fops = { | |
39 | .llseek = generic_file_llseek, | |
40 | .read = do_sync_read, | |
41 | @@ -2166,6 +2170,7 @@ const struct file_operations ocfs2_fops | |
42 | #ifdef CONFIG_COMPAT | |
43 | .compat_ioctl = ocfs2_compat_ioctl, | |
44 | #endif | |
45 | + .lock = ocfs2_lock, | |
46 | .flock = ocfs2_flock, | |
47 | .splice_read = ocfs2_file_splice_read, | |
48 | .splice_write = ocfs2_file_splice_write, | |
49 | @@ -2175,6 +2180,52 @@ const struct file_operations ocfs2_dops | |
50 | .llseek = generic_file_llseek, | |
51 | .read = generic_read_dir, | |
52 | .readdir = ocfs2_readdir, | |
53 | + .fsync = ocfs2_sync_file, | |
54 | + .release = ocfs2_dir_release, | |
55 | + .open = ocfs2_dir_open, | |
56 | + .unlocked_ioctl = ocfs2_ioctl, | |
57 | +#ifdef CONFIG_COMPAT | |
58 | + .compat_ioctl = ocfs2_compat_ioctl, | |
59 | +#endif | |
60 | + .lock = ocfs2_lock, | |
61 | + .flock = ocfs2_flock, | |
62 | +}; | |
63 | + | |
64 | +/* | |
65 | + * POSIX-lockless variants of our file_operations. | |
66 | + * | |
67 | + * These will be used if the underlying cluster stack does not support | |
68 | + * posix file locking, if the user passes the "localflocks" mount | |
69 | + * option, or if we have a local-only fs. | |
70 | + * | |
71 | + * ocfs2_flock is in here because all stacks handle UNIX file locks, | |
72 | + * so we still want it in the case of no stack support for | |
73 | + * plocks. Internally, it will do the right thing when asked to ignore | |
74 | + * the cluster. | |
75 | + */ | |
76 | +const struct file_operations ocfs2_fops_no_plocks = { | |
77 | + .llseek = generic_file_llseek, | |
78 | + .read = do_sync_read, | |
79 | + .write = do_sync_write, | |
80 | + .mmap = ocfs2_mmap, | |
81 | + .fsync = ocfs2_sync_file, | |
82 | + .release = ocfs2_file_release, | |
83 | + .open = ocfs2_file_open, | |
84 | + .aio_read = ocfs2_file_aio_read, | |
85 | + .aio_write = ocfs2_file_aio_write, | |
86 | + .unlocked_ioctl = ocfs2_ioctl, | |
87 | +#ifdef CONFIG_COMPAT | |
88 | + .compat_ioctl = ocfs2_compat_ioctl, | |
89 | +#endif | |
90 | + .flock = ocfs2_flock, | |
91 | + .splice_read = ocfs2_file_splice_read, | |
92 | + .splice_write = ocfs2_file_splice_write, | |
93 | +}; | |
94 | + | |
95 | +const struct file_operations ocfs2_dops_no_plocks = { | |
96 | + .llseek = generic_file_llseek, | |
97 | + .read = generic_read_dir, | |
98 | + .readdir = ocfs2_readdir, | |
99 | .fsync = ocfs2_sync_file, | |
100 | .release = ocfs2_dir_release, | |
101 | .open = ocfs2_dir_open, | |
102 | --- a/fs/ocfs2/file.h | |
103 | +++ b/fs/ocfs2/file.h | |
104 | @@ -28,6 +28,8 @@ | |
105 | ||
106 | extern const struct file_operations ocfs2_fops; | |
107 | extern const struct file_operations ocfs2_dops; | |
108 | +extern const struct file_operations ocfs2_fops_no_plocks; | |
109 | +extern const struct file_operations ocfs2_dops_no_plocks; | |
110 | extern const struct inode_operations ocfs2_file_iops; | |
111 | extern const struct inode_operations ocfs2_special_file_iops; | |
112 | struct ocfs2_alloc_context; | |
113 | --- a/fs/ocfs2/inode.c | |
114 | +++ b/fs/ocfs2/inode.c | |
115 | @@ -220,6 +220,7 @@ int ocfs2_populate_inode(struct inode *i | |
116 | struct super_block *sb; | |
117 | struct ocfs2_super *osb; | |
118 | int status = -EINVAL; | |
119 | + int use_plocks = 1; | |
120 | ||
121 | mlog_entry("(0x%p, size:%llu)\n", inode, | |
122 | (unsigned long long)le64_to_cpu(fe->i_size)); | |
123 | @@ -227,6 +228,10 @@ int ocfs2_populate_inode(struct inode *i | |
124 | sb = inode->i_sb; | |
125 | osb = OCFS2_SB(sb); | |
126 | ||
127 | + if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) || | |
128 | + ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks()) | |
129 | + use_plocks = 0; | |
130 | + | |
131 | /* this means that read_inode cannot create a superblock inode | |
132 | * today. change if needed. */ | |
133 | if (!OCFS2_IS_VALID_DINODE(fe) || | |
134 | @@ -296,13 +301,19 @@ int ocfs2_populate_inode(struct inode *i | |
135 | ||
136 | switch (inode->i_mode & S_IFMT) { | |
137 | case S_IFREG: | |
138 | - inode->i_fop = &ocfs2_fops; | |
139 | + if (use_plocks) | |
140 | + inode->i_fop = &ocfs2_fops; | |
141 | + else | |
142 | + inode->i_fop = &ocfs2_fops_no_plocks; | |
143 | inode->i_op = &ocfs2_file_iops; | |
144 | i_size_write(inode, le64_to_cpu(fe->i_size)); | |
145 | break; | |
146 | case S_IFDIR: | |
147 | inode->i_op = &ocfs2_dir_iops; | |
148 | - inode->i_fop = &ocfs2_dops; | |
149 | + if (use_plocks) | |
150 | + inode->i_fop = &ocfs2_dops; | |
151 | + else | |
152 | + inode->i_fop = &ocfs2_dops_no_plocks; | |
153 | i_size_write(inode, le64_to_cpu(fe->i_size)); | |
154 | break; | |
155 | case S_IFLNK: | |
156 | --- a/fs/ocfs2/locks.c | |
157 | +++ b/fs/ocfs2/locks.c | |
158 | @@ -24,6 +24,7 @@ | |
159 | */ | |
160 | ||
161 | #include <linux/fs.h> | |
162 | +#include <linux/fcntl.h> | |
163 | ||
164 | #define MLOG_MASK_PREFIX ML_INODE | |
165 | #include <cluster/masklog.h> | |
166 | @@ -32,6 +33,7 @@ | |
167 | ||
168 | #include "dlmglue.h" | |
169 | #include "file.h" | |
170 | +#include "inode.h" | |
171 | #include "locks.h" | |
172 | ||
173 | static int ocfs2_do_flock(struct file *file, struct inode *inode, | |
174 | @@ -123,3 +125,16 @@ int ocfs2_flock(struct file *file, int c | |
175 | else | |
176 | return ocfs2_do_flock(file, inode, cmd, fl); | |
177 | } | |
178 | + | |
179 | +int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl) | |
180 | +{ | |
181 | + struct inode *inode = file->f_mapping->host; | |
182 | + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | |
183 | + | |
184 | + if (!(fl->fl_flags & FL_POSIX)) | |
185 | + return -ENOLCK; | |
186 | + if (__mandatory_lock(inode)) | |
187 | + return -ENOLCK; | |
188 | + | |
189 | + return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl); | |
190 | +} | |
191 | --- a/fs/ocfs2/locks.h | |
192 | +++ b/fs/ocfs2/locks.h | |
193 | @@ -27,5 +27,6 @@ | |
194 | #define OCFS2_LOCKS_H | |
195 | ||
196 | int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl); | |
197 | +int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl); | |
198 | ||
199 | #endif /* OCFS2_LOCKS_H */ | |
200 | --- a/fs/ocfs2/stack_user.c | |
201 | +++ b/fs/ocfs2/stack_user.c | |
202 | @@ -28,6 +28,7 @@ | |
203 | #include "ocfs2.h" /* For struct ocfs2_lock_res */ | |
204 | #include "stackglue.h" | |
205 | ||
206 | +#include <linux/dlm_plock.h> | |
207 | ||
208 | /* | |
209 | * The control protocol starts with a handshake. Until the handshake | |
210 | @@ -746,6 +747,37 @@ static void user_dlm_dump_lksb(union ocf | |
211 | { | |
212 | } | |
213 | ||
214 | +static int user_plock(struct ocfs2_cluster_connection *conn, | |
215 | + u64 ino, | |
216 | + struct file *file, | |
217 | + int cmd, | |
218 | + struct file_lock *fl) | |
219 | +{ | |
220 | + /* | |
221 | + * This more or less just demuxes the plock request into any | |
222 | + * one of three dlm calls. | |
223 | + * | |
224 | + * Internally, fs/dlm will pass these to a misc device, which | |
225 | + * a userspace daemon will read and write to. | |
226 | + * | |
227 | + * For now, cancel requests (which happen internally only), | |
228 | + * are turned into unlocks. Most of this function taken from | |
229 | + * gfs2_lock. | |
230 | + */ | |
231 | + | |
232 | + if (cmd == F_CANCELLK) { | |
233 | + cmd = F_SETLK; | |
234 | + fl->fl_type = F_UNLCK; | |
235 | + } | |
236 | + | |
237 | + if (IS_GETLK(cmd)) | |
238 | + return dlm_posix_get(conn->cc_lockspace, ino, file, fl); | |
239 | + else if (fl->fl_type == F_UNLCK) | |
240 | + return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl); | |
241 | + else | |
242 | + return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl); | |
243 | +} | |
244 | + | |
245 | /* | |
246 | * Compare a requested locking protocol version against the current one. | |
247 | * | |
248 | @@ -839,6 +871,7 @@ static struct ocfs2_stack_operations ocf | |
249 | .dlm_unlock = user_dlm_unlock, | |
250 | .lock_status = user_dlm_lock_status, | |
251 | .lock_lvb = user_dlm_lvb, | |
252 | + .plock = user_plock, | |
253 | .dump_lksb = user_dlm_dump_lksb, | |
254 | }; | |
255 | ||
256 | --- a/fs/ocfs2/stackglue.c | |
257 | +++ b/fs/ocfs2/stackglue.c | |
258 | @@ -288,6 +288,26 @@ void ocfs2_dlm_dump_lksb(union ocfs2_dlm | |
259 | } | |
260 | EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb); | |
261 | ||
262 | +int ocfs2_stack_supports_plocks(void) | |
263 | +{ | |
264 | + return !!(active_stack && active_stack->sp_ops->plock); | |
265 | +} | |
266 | +EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks); | |
267 | + | |
268 | +/* | |
269 | + * ocfs2_plock() can only be safely called if | |
270 | + * ocfs2_stack_supports_plocks() returned true | |
271 | + */ | |
272 | +int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, | |
273 | + struct file *file, int cmd, struct file_lock *fl) | |
274 | +{ | |
275 | + WARN_ON_ONCE(active_stack->sp_ops->plock == NULL); | |
276 | + if (active_stack->sp_ops->plock) | |
277 | + return active_stack->sp_ops->plock(conn, ino, file, cmd, fl); | |
278 | + return -EOPNOTSUPP; | |
279 | +} | |
280 | +EXPORT_SYMBOL_GPL(ocfs2_plock); | |
281 | + | |
282 | int ocfs2_cluster_connect(const char *stack_name, | |
283 | const char *group, | |
284 | int grouplen, | |
285 | --- a/fs/ocfs2/stackglue.h | |
286 | +++ b/fs/ocfs2/stackglue.h | |
287 | @@ -28,6 +28,10 @@ | |
288 | #include "dlm/dlmapi.h" | |
289 | #include <linux/dlm.h> | |
290 | ||
291 | +/* Needed for plock-related prototypes */ | |
292 | +struct file; | |
293 | +struct file_lock; | |
294 | + | |
295 | /* | |
296 | * dlmconstants.h does not have a LOCAL flag. We hope to remove it | |
297 | * some day, but right now we need it. Let's fake it. This value is larger | |
298 | @@ -187,6 +191,17 @@ struct ocfs2_stack_operations { | |
299 | void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb); | |
300 | ||
301 | /* | |
302 | + * Cluster-aware posix locks | |
303 | + * | |
304 | + * This is NULL for stacks which do not support posix locks. | |
305 | + */ | |
306 | + int (*plock)(struct ocfs2_cluster_connection *conn, | |
307 | + u64 ino, | |
308 | + struct file *file, | |
309 | + int cmd, | |
310 | + struct file_lock *fl); | |
311 | + | |
312 | + /* | |
313 | * This is an optoinal debugging hook. If provided, the | |
314 | * stack can dump debugging information about this lock. | |
315 | */ | |
316 | @@ -240,6 +255,10 @@ int ocfs2_dlm_lock_status(union ocfs2_dl | |
317 | void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb); | |
318 | void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb); | |
319 | ||
320 | +int ocfs2_stack_supports_plocks(void); | |
321 | +int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino, | |
322 | + struct file *file, int cmd, struct file_lock *fl); | |
323 | + | |
324 | void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto); | |
325 | ||
326 |