1 /* 2 * linux/fs/9p/vfs_file.c 3 * 4 * This file contians vfs file ops for 9P2000. 5 * 6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 7 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 11 * as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to: 20 * Free Software Foundation 21 * 51 Franklin Street, Fifth Floor 22 * Boston, MA 02111-1301 USA 23 * 24 */ 25 26 #include <linux/module.h> 27 #include <linux/errno.h> 28 #include <linux/fs.h> 29 #include <linux/sched.h> 30 #include <linux/file.h> 31 #include <linux/stat.h> 32 #include <linux/string.h> 33 #include <linux/inet.h> 34 #include <linux/list.h> 35 #include <linux/pagemap.h> 36 #include <linux/utsname.h> 37 #include <asm/uaccess.h> 38 #include <linux/idr.h> 39 #include <net/9p/9p.h> 40 #include <net/9p/client.h> 41 42 #include "v9fs.h" 43 #include "v9fs_vfs.h" 44 #include "fid.h" 45 #include "cache.h" 46 47 /** 48 * v9fs_file_open - open a file (or directory) 49 * @inode: inode to be opened 50 * @file: file being opened 51 * 52 */ 53 54 int v9fs_file_open(struct inode *inode, struct file *file) 55 { 56 int err; 57 struct v9fs_session_info *v9ses; 58 struct p9_fid *fid; 59 int omode; 60 61 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); 62 v9ses = v9fs_inode2v9ses(inode); 63 if (v9fs_proto_dotl(v9ses)) 64 omode = file->f_flags; 65 else 66 omode = v9fs_uflags2omode(file->f_flags, 67 v9fs_proto_dotu(v9ses)); 68 fid = file->private_data; 69 if (!fid) { 70 fid = v9fs_fid_clone(file->f_path.dentry); 71 if (IS_ERR(fid)) 72 return PTR_ERR(fid); 73 74 err = p9_client_open(fid, omode); 75 if (err < 0) { 76 p9_client_clunk(fid); 77 return err; 78 } 79 if (file->f_flags & O_TRUNC) { 80 i_size_write(inode, 0); 81 inode->i_blocks = 0; 82 } 83 if ((file->f_flags & O_APPEND) && 84 (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))) 85 generic_file_llseek(file, 0, SEEK_END); 86 } 87 88 file->private_data = fid; 89 #ifdef CONFIG_9P_FSCACHE 90 if (v9ses->cache) 91 v9fs_cache_inode_set_cookie(inode, file); 92 #endif 93 return 0; 94 } 95 96 /** 97 * v9fs_file_lock - lock a file (or directory) 98 * @filp: file to be locked 99 * @cmd: lock command 100 * @fl: file lock structure 101 * 102 * Bugs: this looks like a local only lock, we should extend into 9P 103 * by using open exclusive 104 */ 105 106 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) 107 { 108 int res = 0; 109 struct inode *inode = filp->f_path.dentry->d_inode; 110 111 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); 112 113 /* No mandatory locks */ 114 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) 115 return -ENOLCK; 116 117 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { 118 filemap_write_and_wait(inode->i_mapping); 119 invalidate_mapping_pages(&inode->i_data, 0, -1); 120 } 121 122 return res; 123 } 124 125 static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) 126 { 127 struct p9_flock flock; 128 struct p9_fid *fid; 129 uint8_t status; 130 int res = 0; 131 unsigned char fl_type; 132 133 fid = filp->private_data; 134 BUG_ON(fid == NULL); 135 136 if ((fl->fl_flags & FL_POSIX) != FL_POSIX) 137 BUG(); 138 139 res = posix_lock_file_wait(filp, fl); 140 if (res < 0) 141 goto out; 142 143 /* convert posix lock to p9 tlock args */ 144 memset(&flock, 0, sizeof(flock)); 145 flock.type = fl->fl_type; 146 flock.start = fl->fl_start; 147 if (fl->fl_end == OFFSET_MAX) 148 flock.length = 0; 149 else 150 flock.length = fl->fl_end - fl->fl_start + 1; 151 flock.proc_id = fl->fl_pid; 152 flock.client_id = utsname()->nodename; 153 if (IS_SETLKW(cmd)) 154 flock.flags = P9_LOCK_FLAGS_BLOCK; 155 156 /* 157 * if its a blocked request and we get P9_LOCK_BLOCKED as the status 158 * for lock request, keep on trying 159 */ 160 for (;;) { 161 res = p9_client_lock_dotl(fid, &flock, &status); 162 if (res < 0) 163 break; 164 165 if (status != P9_LOCK_BLOCKED) 166 break; 167 if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) 168 break; 169 schedule_timeout_interruptible(P9_LOCK_TIMEOUT); 170 } 171 172 /* map 9p status to VFS status */ 173 switch (status) { 174 case P9_LOCK_SUCCESS: 175 res = 0; 176 break; 177 case P9_LOCK_BLOCKED: 178 res = -EAGAIN; 179 break; 180 case P9_LOCK_ERROR: 181 case P9_LOCK_GRACE: 182 res = -ENOLCK; 183 break; 184 default: 185 BUG(); 186 } 187 188 /* 189 * incase server returned error for lock request, revert 190 * it locally 191 */ 192 if (res < 0 && fl->fl_type != F_UNLCK) { 193 fl_type = fl->fl_type; 194 fl->fl_type = F_UNLCK; 195 res = posix_lock_file_wait(filp, fl); 196 fl->fl_type = fl_type; 197 } 198 out: 199 return res; 200 } 201 202 static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) 203 { 204 struct p9_getlock glock; 205 struct p9_fid *fid; 206 int res = 0; 207 208 fid = filp->private_data; 209 BUG_ON(fid == NULL); 210 211 posix_test_lock(filp, fl); 212 /* 213 * if we have a conflicting lock locally, no need to validate 214 * with server 215 */ 216 if (fl->fl_type != F_UNLCK) 217 return res; 218 219 /* convert posix lock to p9 tgetlock args */ 220 memset(&glock, 0, sizeof(glock)); 221 glock.type = fl->fl_type; 222 glock.start = fl->fl_start; 223 if (fl->fl_end == OFFSET_MAX) 224 glock.length = 0; 225 else 226 glock.length = fl->fl_end - fl->fl_start + 1; 227 glock.proc_id = fl->fl_pid; 228 glock.client_id = utsname()->nodename; 229 230 res = p9_client_getlock_dotl(fid, &glock); 231 if (res < 0) 232 return res; 233 if (glock.type != F_UNLCK) { 234 fl->fl_type = glock.type; 235 fl->fl_start = glock.start; 236 if (glock.length == 0) 237 fl->fl_end = OFFSET_MAX; 238 else 239 fl->fl_end = glock.start + glock.length - 1; 240 fl->fl_pid = glock.proc_id; 241 } else 242 fl->fl_type = F_UNLCK; 243 244 return res; 245 } 246 247 /** 248 * v9fs_file_lock_dotl - lock a file (or directory) 249 * @filp: file to be locked 250 * @cmd: lock command 251 * @fl: file lock structure 252 * 253 */ 254 255 static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl) 256 { 257 struct inode *inode = filp->f_path.dentry->d_inode; 258 int ret = -ENOLCK; 259 260 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp, 261 cmd, fl, filp->f_path.dentry->d_name.name); 262 263 /* No mandatory locks */ 264 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) 265 goto out_err; 266 267 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { 268 filemap_write_and_wait(inode->i_mapping); 269 invalidate_mapping_pages(&inode->i_data, 0, -1); 270 } 271 272 if (IS_SETLK(cmd) || IS_SETLKW(cmd)) 273 ret = v9fs_file_do_lock(filp, cmd, fl); 274 else if (IS_GETLK(cmd)) 275 ret = v9fs_file_getlock(filp, fl); 276 else 277 ret = -EINVAL; 278 out_err: 279 return ret; 280 } 281 282 /** 283 * v9fs_file_flock_dotl - lock a file 284 * @filp: file to be locked 285 * @cmd: lock command 286 * @fl: file lock structure 287 * 288 */ 289 290 static int v9fs_file_flock_dotl(struct file *filp, int cmd, 291 struct file_lock *fl) 292 { 293 struct inode *inode = filp->f_path.dentry->d_inode; 294 int ret = -ENOLCK; 295 296 P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp, 297 cmd, fl, filp->f_path.dentry->d_name.name); 298 299 /* No mandatory locks */ 300 if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) 301 goto out_err; 302 303 if (!(fl->fl_flags & FL_FLOCK)) 304 goto out_err; 305 306 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { 307 filemap_write_and_wait(inode->i_mapping); 308 invalidate_mapping_pages(&inode->i_data, 0, -1); 309 } 310 /* Convert flock to posix lock */ 311 fl->fl_owner = (fl_owner_t)filp; 312 fl->fl_start = 0; 313 fl->fl_end = OFFSET_MAX; 314 fl->fl_flags |= FL_POSIX; 315 fl->fl_flags ^= FL_FLOCK; 316 317 if (IS_SETLK(cmd) | IS_SETLKW(cmd)) 318 ret = v9fs_file_do_lock(filp, cmd, fl); 319 else 320 ret = -EINVAL; 321 out_err: 322 return ret; 323 } 324 325 /** 326 * v9fs_file_readn - read from a file 327 * @filp: file pointer to read 328 * @data: data buffer to read data into 329 * @udata: user data buffer to read data into 330 * @count: size of buffer 331 * @offset: offset at which to read data 332 * 333 */ 334 335 ssize_t 336 v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, 337 u64 offset) 338 { 339 int n, total, size; 340 struct p9_fid *fid = filp->private_data; 341 342 P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid, 343 (long long unsigned) offset, count); 344 345 n = 0; 346 total = 0; 347 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; 348 do { 349 n = p9_client_read(fid, data, udata, offset, count); 350 if (n <= 0) 351 break; 352 353 if (data) 354 data += n; 355 if (udata) 356 udata += n; 357 358 offset += n; 359 count -= n; 360 total += n; 361 } while (count > 0 && n == size); 362 363 if (n < 0) 364 total = n; 365 366 return total; 367 } 368 369 /** 370 * v9fs_file_read - read from a file 371 * @filp: file pointer to read 372 * @udata: user data buffer to read data into 373 * @count: size of buffer 374 * @offset: offset at which to read data 375 * 376 */ 377 378 static ssize_t 379 v9fs_file_read(struct file *filp, char __user *udata, size_t count, 380 loff_t * offset) 381 { 382 int ret; 383 struct p9_fid *fid; 384 size_t size; 385 386 P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset); 387 fid = filp->private_data; 388 389 size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; 390 if (count > size) 391 ret = v9fs_file_readn(filp, NULL, udata, count, *offset); 392 else 393 ret = p9_client_read(fid, NULL, udata, *offset, count); 394 395 if (ret > 0) 396 *offset += ret; 397 398 return ret; 399 } 400 401 /** 402 * v9fs_file_write - write to a file 403 * @filp: file pointer to write 404 * @data: data buffer to write data from 405 * @count: size of buffer 406 * @offset: offset at which to write data 407 * 408 */ 409 410 static ssize_t 411 v9fs_file_write(struct file *filp, const char __user * data, 412 size_t count, loff_t * offset) 413 { 414 ssize_t retval; 415 size_t total = 0; 416 int n; 417 struct p9_fid *fid; 418 struct p9_client *clnt; 419 struct inode *inode = filp->f_path.dentry->d_inode; 420 loff_t origin = *offset; 421 unsigned long pg_start, pg_end; 422 423 P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, 424 (int)count, (int)*offset); 425 426 fid = filp->private_data; 427 clnt = fid->clnt; 428 429 retval = generic_write_checks(filp, &origin, &count, 0); 430 if (retval) 431 goto out; 432 433 retval = -EINVAL; 434 if ((ssize_t) count < 0) 435 goto out; 436 retval = 0; 437 if (!count) 438 goto out; 439 440 do { 441 n = p9_client_write(fid, NULL, data+total, origin+total, count); 442 if (n <= 0) 443 break; 444 count -= n; 445 total += n; 446 } while (count > 0); 447 448 if (total > 0) { 449 pg_start = origin >> PAGE_CACHE_SHIFT; 450 pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT; 451 if (inode->i_mapping && inode->i_mapping->nrpages) 452 invalidate_inode_pages2_range(inode->i_mapping, 453 pg_start, pg_end); 454 *offset += total; 455 i_size_write(inode, i_size_read(inode) + total); 456 inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; 457 } 458 459 if (n < 0) 460 retval = n; 461 else 462 retval = total; 463 out: 464 return retval; 465 } 466 467 static int v9fs_file_fsync(struct file *filp, int datasync) 468 { 469 struct p9_fid *fid; 470 struct p9_wstat wstat; 471 int retval; 472 473 P9_DPRINTK(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); 474 475 fid = filp->private_data; 476 v9fs_blank_wstat(&wstat); 477 478 retval = p9_client_wstat(fid, &wstat); 479 return retval; 480 } 481 482 int v9fs_file_fsync_dotl(struct file *filp, int datasync) 483 { 484 struct p9_fid *fid; 485 int retval; 486 487 P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n", 488 filp, datasync); 489 490 fid = filp->private_data; 491 492 retval = p9_client_fsync(fid, datasync); 493 return retval; 494 } 495 496 const struct file_operations v9fs_cached_file_operations = { 497 .llseek = generic_file_llseek, 498 .read = do_sync_read, 499 .aio_read = generic_file_aio_read, 500 .write = v9fs_file_write, 501 .open = v9fs_file_open, 502 .release = v9fs_dir_release, 503 .lock = v9fs_file_lock, 504 .mmap = generic_file_readonly_mmap, 505 .fsync = v9fs_file_fsync, 506 }; 507 508 const struct file_operations v9fs_cached_file_operations_dotl = { 509 .llseek = generic_file_llseek, 510 .read = do_sync_read, 511 .aio_read = generic_file_aio_read, 512 .write = v9fs_file_write, 513 .open = v9fs_file_open, 514 .release = v9fs_dir_release, 515 .lock = v9fs_file_lock_dotl, 516 .flock = v9fs_file_flock_dotl, 517 .mmap = generic_file_readonly_mmap, 518 .fsync = v9fs_file_fsync_dotl, 519 }; 520 521 const struct file_operations v9fs_file_operations = { 522 .llseek = generic_file_llseek, 523 .read = v9fs_file_read, 524 .write = v9fs_file_write, 525 .open = v9fs_file_open, 526 .release = v9fs_dir_release, 527 .lock = v9fs_file_lock, 528 .mmap = generic_file_readonly_mmap, 529 .fsync = v9fs_file_fsync, 530 }; 531 532 const struct file_operations v9fs_file_operations_dotl = { 533 .llseek = generic_file_llseek, 534 .read = v9fs_file_read, 535 .write = v9fs_file_write, 536 .open = v9fs_file_open, 537 .release = v9fs_dir_release, 538 .lock = v9fs_file_lock_dotl, 539 .flock = v9fs_file_flock_dotl, 540 .mmap = generic_file_readonly_mmap, 541 .fsync = v9fs_file_fsync_dotl, 542 }; 543