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 /fs | |
| 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>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/9p/v9fs_vfs.h | 2 | ||||
| -rw-r--r-- | fs/9p/vfs_file.c | 160 |
2 files changed, 160 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 | }; |
