diff options
author | M. Mohan Kumar <mohan@in.ibm.com> | 2010-09-27 02:04:24 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2010-10-28 10:08:47 -0400 |
commit | a099027c779068b834f335cfdc3f2bf10f531dd9 (patch) | |
tree | eee43443cce85a03c13b1cfdd25bf451445cf78f | |
parent | 920e65dc6911da28a58e17f4b683302636fc6d8e (diff) |
9p: Implement TLOCK
Synopsis
size[4] TLock tag[2] fid[4] flock[n]
size[4] RLock tag[2] status[1]
Description
Tlock is used to acquire/release byte range posix locks on a file
identified by given fid. The reply contains status of the lock request
flock structure:
type[1] - Type of lock: F_RDLCK, F_WRLCK, F_UNLCK
flags[4] - Flags could be either of
P9_LOCK_FLAGS_BLOCK - Blocked lock request, if there is a
conflicting lock exists, wait for that lock to be released.
P9_LOCK_FLAGS_RECLAIM - Reclaim lock request, used when client is
trying to reclaim a lock after a server restrart (due to crash)
start[8] - Starting offset for lock
length[8] - Number of bytes to lock
If length is 0, lock all bytes starting at the location 'start'
through to the end of file
pid[4] - PID of the process that wants to take lock
client_id[4] - Unique client id
status[1] - Status of the lock request, can be
P9_LOCK_SUCCESS(0), P9_LOCK_BLOCKED(1), P9_LOCK_ERROR(2) or
P9_LOCK_GRACE(3)
P9_LOCK_SUCCESS - Request was successful
P9_LOCK_BLOCKED - A conflicting lock is held by another process
P9_LOCK_ERROR - Error while processing the lock request
P9_LOCK_GRACE - Server is in grace period, it can't accept new lock
requests in this period (except locks with
P9_LOCK_FLAGS_RECLAIM flag set)
Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
-rw-r--r-- | fs/9p/v9fs_vfs.h | 2 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 160 | ||||
-rw-r--r-- | include/net/9p/9p.h | 28 | ||||
-rw-r--r-- | include/net/9p/client.h | 1 | ||||
-rw-r--r-- | net/9p/client.c | 33 |
5 files changed, 222 insertions, 2 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 09861295eef9..d26db1932f7a 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -65,3 +65,5 @@ int v9fs_uflags2omode(int uflags, int extended); | |||
65 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); | 65 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); |
66 | void v9fs_blank_wstat(struct p9_wstat *wstat); | 66 | void v9fs_blank_wstat(struct p9_wstat *wstat); |
67 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); | 67 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); |
68 | |||
69 | #define P9_LOCK_TIMEOUT (30*HZ) | ||
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index fdf303207c72..6f77abd23184 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
34 | #include <linux/list.h> | 34 | #include <linux/list.h> |
35 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
36 | #include <linux/utsname.h> | ||
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
38 | #include <net/9p/9p.h> | 39 | #include <net/9p/9p.h> |
@@ -133,6 +134,159 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
133 | return res; | 134 | return res; |
134 | } | 135 | } |
135 | 136 | ||
137 | static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) | ||
138 | { | ||
139 | struct p9_flock flock; | ||
140 | struct p9_fid *fid; | ||
141 | uint8_t status; | ||
142 | int res = 0; | ||
143 | unsigned char fl_type; | ||
144 | |||
145 | fid = filp->private_data; | ||
146 | BUG_ON(fid == NULL); | ||
147 | |||
148 | if ((fl->fl_flags & FL_POSIX) != FL_POSIX) | ||
149 | BUG(); | ||
150 | |||
151 | res = posix_lock_file_wait(filp, fl); | ||
152 | if (res < 0) | ||
153 | goto out; | ||
154 | |||
155 | /* convert posix lock to p9 tlock args */ | ||
156 | memset(&flock, 0, sizeof(flock)); | ||
157 | flock.type = fl->fl_type; | ||
158 | flock.start = fl->fl_start; | ||
159 | if (fl->fl_end == OFFSET_MAX) | ||
160 | flock.length = 0; | ||
161 | else | ||
162 | flock.length = fl->fl_end - fl->fl_start + 1; | ||
163 | flock.proc_id = fl->fl_pid; | ||
164 | flock.client_id = utsname()->nodename; | ||
165 | if (IS_SETLKW(cmd)) | ||
166 | flock.flags = P9_LOCK_FLAGS_BLOCK; | ||
167 | |||
168 | /* | ||
169 | * if its a blocked request and we get P9_LOCK_BLOCKED as the status | ||
170 | * for lock request, keep on trying | ||
171 | */ | ||
172 | for (;;) { | ||
173 | res = p9_client_lock_dotl(fid, &flock, &status); | ||
174 | if (res < 0) | ||
175 | break; | ||
176 | |||
177 | if (status != P9_LOCK_BLOCKED) | ||
178 | break; | ||
179 | if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) | ||
180 | break; | ||
181 | schedule_timeout_interruptible(P9_LOCK_TIMEOUT); | ||
182 | } | ||
183 | |||
184 | /* map 9p status to VFS status */ | ||
185 | switch (status) { | ||
186 | case P9_LOCK_SUCCESS: | ||
187 | res = 0; | ||
188 | break; | ||
189 | case P9_LOCK_BLOCKED: | ||
190 | res = -EAGAIN; | ||
191 | break; | ||
192 | case P9_LOCK_ERROR: | ||
193 | case P9_LOCK_GRACE: | ||
194 | res = -ENOLCK; | ||
195 | break; | ||
196 | default: | ||
197 | BUG(); | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * incase server returned error for lock request, revert | ||
202 | * it locally | ||
203 | */ | ||
204 | if (res < 0 && fl->fl_type != F_UNLCK) { | ||
205 | fl_type = fl->fl_type; | ||
206 | fl->fl_type = F_UNLCK; | ||
207 | res = posix_lock_file_wait(filp, fl); | ||
208 | fl->fl_type = fl_type; | ||
209 | } | ||
210 | out: | ||
211 | return res; | ||
212 | } | ||
213 | |||
214 | /** | ||
215 | * v9fs_file_lock_dotl - lock a file (or directory) | ||
216 | * @filp: file to be locked | ||
217 | * @cmd: lock command | ||
218 | * @fl: file lock structure | ||
219 | * | ||
220 | */ | ||
221 | |||
222 | static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl) | ||
223 | { | ||
224 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
225 | int ret = -ENOLCK; | ||
226 | |||
227 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp, | ||
228 | cmd, fl, filp->f_path.dentry->d_name.name); | ||
229 | |||
230 | /* No mandatory locks */ | ||
231 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) | ||
232 | goto out_err; | ||
233 | |||
234 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | ||
235 | filemap_write_and_wait(inode->i_mapping); | ||
236 | invalidate_mapping_pages(&inode->i_data, 0, -1); | ||
237 | } | ||
238 | |||
239 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) | ||
240 | ret = v9fs_file_do_lock(filp, cmd, fl); | ||
241 | else | ||
242 | ret = -EINVAL; | ||
243 | out_err: | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * v9fs_file_flock_dotl - lock a file | ||
249 | * @filp: file to be locked | ||
250 | * @cmd: lock command | ||
251 | * @fl: file lock structure | ||
252 | * | ||
253 | */ | ||
254 | |||
255 | static int v9fs_file_flock_dotl(struct file *filp, int cmd, | ||
256 | struct file_lock *fl) | ||
257 | { | ||
258 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
259 | int ret = -ENOLCK; | ||
260 | |||
261 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp, | ||
262 | cmd, fl, filp->f_path.dentry->d_name.name); | ||
263 | |||
264 | /* No mandatory locks */ | ||
265 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) | ||
266 | goto out_err; | ||
267 | |||
268 | if (!(fl->fl_flags & FL_FLOCK)) | ||
269 | goto out_err; | ||
270 | |||
271 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | ||
272 | filemap_write_and_wait(inode->i_mapping); | ||
273 | invalidate_mapping_pages(&inode->i_data, 0, -1); | ||
274 | } | ||
275 | /* Convert flock to posix lock */ | ||
276 | fl->fl_owner = (fl_owner_t)filp; | ||
277 | fl->fl_start = 0; | ||
278 | fl->fl_end = OFFSET_MAX; | ||
279 | fl->fl_flags |= FL_POSIX; | ||
280 | fl->fl_flags ^= FL_FLOCK; | ||
281 | |||
282 | if (IS_SETLK(cmd) | IS_SETLKW(cmd)) | ||
283 | ret = v9fs_file_do_lock(filp, cmd, fl); | ||
284 | else | ||
285 | ret = -EINVAL; | ||
286 | out_err: | ||
287 | return ret; | ||
288 | } | ||
289 | |||
136 | /** | 290 | /** |
137 | * v9fs_file_readn - read from a file | 291 | * v9fs_file_readn - read from a file |
138 | * @filp: file pointer to read | 292 | * @filp: file pointer to read |
@@ -323,7 +477,8 @@ static const struct file_operations v9fs_cached_file_operations_dotl = { | |||
323 | .write = v9fs_file_write, | 477 | .write = v9fs_file_write, |
324 | .open = v9fs_file_open, | 478 | .open = v9fs_file_open, |
325 | .release = v9fs_dir_release, | 479 | .release = v9fs_dir_release, |
326 | .lock = v9fs_file_lock, | 480 | .lock = v9fs_file_lock_dotl, |
481 | .flock = v9fs_file_flock_dotl, | ||
327 | .mmap = generic_file_readonly_mmap, | 482 | .mmap = generic_file_readonly_mmap, |
328 | .fsync = v9fs_file_fsync_dotl, | 483 | .fsync = v9fs_file_fsync_dotl, |
329 | }; | 484 | }; |
@@ -345,7 +500,8 @@ const struct file_operations v9fs_file_operations_dotl = { | |||
345 | .write = v9fs_file_write, | 500 | .write = v9fs_file_write, |
346 | .open = v9fs_file_open, | 501 | .open = v9fs_file_open, |
347 | .release = v9fs_dir_release, | 502 | .release = v9fs_dir_release, |
348 | .lock = v9fs_file_lock, | 503 | .lock = v9fs_file_lock_dotl, |
504 | .flock = v9fs_file_flock_dotl, | ||
349 | .mmap = generic_file_readonly_mmap, | 505 | .mmap = generic_file_readonly_mmap, |
350 | .fsync = v9fs_file_fsync_dotl, | 506 | .fsync = v9fs_file_fsync_dotl, |
351 | }; | 507 | }; |
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 55e96057f47f..1859a2560cc5 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h | |||
@@ -165,6 +165,8 @@ enum p9_msg_t { | |||
165 | P9_RREADDIR, | 165 | P9_RREADDIR, |
166 | P9_TFSYNC = 50, | 166 | P9_TFSYNC = 50, |
167 | P9_RFSYNC, | 167 | P9_RFSYNC, |
168 | P9_TLOCK = 52, | ||
169 | P9_RLOCK, | ||
168 | P9_TLINK = 70, | 170 | P9_TLINK = 70, |
169 | P9_RLINK, | 171 | P9_RLINK, |
170 | P9_TMKDIR = 72, | 172 | P9_TMKDIR = 72, |
@@ -464,6 +466,32 @@ struct p9_iattr_dotl { | |||
464 | u64 mtime_nsec; | 466 | u64 mtime_nsec; |
465 | }; | 467 | }; |
466 | 468 | ||
469 | #define P9_LOCK_SUCCESS 0 | ||
470 | #define P9_LOCK_BLOCKED 1 | ||
471 | #define P9_LOCK_ERROR 2 | ||
472 | #define P9_LOCK_GRACE 3 | ||
473 | |||
474 | #define P9_LOCK_FLAGS_BLOCK 1 | ||
475 | #define P9_LOCK_FLAGS_RECLAIM 2 | ||
476 | |||
477 | /* struct p9_flock: POSIX lock structure | ||
478 | * @type - type of lock | ||
479 | * @flags - lock flags | ||
480 | * @start - starting offset of the lock | ||
481 | * @length - number of bytes | ||
482 | * @proc_id - process id which wants to take lock | ||
483 | * @client_id - client id | ||
484 | */ | ||
485 | |||
486 | struct p9_flock { | ||
487 | u8 type; | ||
488 | u32 flags; | ||
489 | u64 start; | ||
490 | u64 length; | ||
491 | u32 proc_id; | ||
492 | char *client_id; | ||
493 | }; | ||
494 | |||
467 | /* Structures for Protocol Operations */ | 495 | /* Structures for Protocol Operations */ |
468 | struct p9_tstatfs { | 496 | struct p9_tstatfs { |
469 | u32 fid; | 497 | u32 fid; |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 8744e3ad4a07..d7dcb142e3bb 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -249,6 +249,7 @@ int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode, | |||
249 | dev_t rdev, gid_t gid, struct p9_qid *); | 249 | dev_t rdev, gid_t gid, struct p9_qid *); |
250 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, | 250 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, |
251 | gid_t gid, struct p9_qid *); | 251 | gid_t gid, struct p9_qid *); |
252 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); | ||
252 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); | 253 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); |
253 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req); | 254 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req); |
254 | 255 | ||
diff --git a/net/9p/client.c b/net/9p/client.c index 30c4a1b224fb..fbd2b195801c 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -1803,3 +1803,36 @@ error: | |||
1803 | 1803 | ||
1804 | } | 1804 | } |
1805 | EXPORT_SYMBOL(p9_client_mkdir_dotl); | 1805 | EXPORT_SYMBOL(p9_client_mkdir_dotl); |
1806 | |||
1807 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) | ||
1808 | { | ||
1809 | int err; | ||
1810 | struct p9_client *clnt; | ||
1811 | struct p9_req_t *req; | ||
1812 | |||
1813 | err = 0; | ||
1814 | clnt = fid->clnt; | ||
1815 | P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d " | ||
1816 | "start %lld length %lld proc_id %d client_id %s\n", | ||
1817 | fid->fid, flock->type, flock->flags, flock->start, | ||
1818 | flock->length, flock->proc_id, flock->client_id); | ||
1819 | |||
1820 | req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type, | ||
1821 | flock->flags, flock->start, flock->length, | ||
1822 | flock->proc_id, flock->client_id); | ||
1823 | |||
1824 | if (IS_ERR(req)) | ||
1825 | return PTR_ERR(req); | ||
1826 | |||
1827 | err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); | ||
1828 | if (err) { | ||
1829 | p9pdu_dump(1, req->rc); | ||
1830 | goto error; | ||
1831 | } | ||
1832 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); | ||
1833 | error: | ||
1834 | p9_free_req(clnt, req); | ||
1835 | return err; | ||
1836 | |||
1837 | } | ||
1838 | EXPORT_SYMBOL(p9_client_lock_dotl); | ||