1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * This file contians vfs file ops for 9P2000. 4 * 5 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 6 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 7 */ 8 9 #include <linux/module.h> 10 #include <linux/errno.h> 11 #include <linux/fs.h> 12 #include <linux/filelock.h> 13 #include <linux/sched.h> 14 #include <linux/file.h> 15 #include <linux/stat.h> 16 #include <linux/string.h> 17 #include <linux/list.h> 18 #include <linux/pagemap.h> 19 #include <linux/utsname.h> 20 #include <linux/uaccess.h> 21 #include <linux/uio.h> 22 #include <linux/slab.h> 23 #include <net/9p/9p.h> 24 #include <net/9p/client.h> 25 26 #include "v9fs.h" 27 #include "v9fs_vfs.h" 28 #include "fid.h" 29 #include "cache.h" 30 31 static const struct vm_operations_struct v9fs_mmap_file_vm_ops; 32 33 /** 34 * v9fs_file_open - open a file (or directory) 35 * @inode: inode to be opened 36 * @file: file being opened 37 * 38 */ 39 40 int v9fs_file_open(struct inode *inode, struct file *file) 41 { 42 int err; 43 struct v9fs_session_info *v9ses; 44 struct p9_fid *fid; 45 int omode; 46 47 p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); 48 v9ses = v9fs_inode2v9ses(inode); 49 if (v9fs_proto_dotl(v9ses)) 50 omode = v9fs_open_to_dotl_flags(file->f_flags); 51 else 52 omode = v9fs_uflags2omode(file->f_flags, 53 v9fs_proto_dotu(v9ses)); 54 fid = file->private_data; 55 if (!fid) { 56 fid = v9fs_fid_clone(file_dentry(file)); 57 if (IS_ERR(fid)) 58 return PTR_ERR(fid); 59 60 if ((v9ses->cache & CACHE_WRITEBACK) && (omode & P9_OWRITE)) { 61 int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR; 62 63 p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n"); 64 err = p9_client_open(fid, writeback_omode); 65 if (err < 0) { 66 p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n"); 67 err = p9_client_open(fid, omode); 68 fid->mode |= P9L_DIRECT; 69 } 70 } else { 71 err = p9_client_open(fid, omode); 72 } 73 if (err < 0) { 74 p9_fid_put(fid); 75 return err; 76 } 77 if ((file->f_flags & O_APPEND) && 78 (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))) 79 generic_file_llseek(file, 0, SEEK_END); 80 81 file->private_data = fid; 82 } 83 84 #ifdef CONFIG_9P_FSCACHE 85 if (v9ses->cache & CACHE_FSCACHE) 86 fscache_use_cookie(v9fs_inode_cookie(V9FS_I(inode)), 87 file->f_mode & FMODE_WRITE); 88 #endif 89 v9fs_fid_add_modes(fid, v9ses->flags, v9ses->cache, file->f_flags); 90 v9fs_open_fid_add(inode, &fid); 91 return 0; 92 } 93 94 /** 95 * v9fs_file_lock - lock a file (or directory) 96 * @filp: file to be locked 97 * @cmd: lock command 98 * @fl: file lock structure 99 * 100 * Bugs: this looks like a local only lock, we should extend into 9P 101 * by using open exclusive 102 */ 103 104 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) 105 { 106 struct inode *inode = file_inode(filp); 107 108 p9_debug(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); 109 110 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->c.flc_type != F_UNLCK) { 111 filemap_write_and_wait(inode->i_mapping); 112 invalidate_mapping_pages(&inode->i_data, 0, -1); 113 } 114 115 return 0; 116 } 117 118 static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) 119 { 120 struct p9_flock flock; 121 struct p9_fid *fid; 122 uint8_t status = P9_LOCK_ERROR; 123 int res = 0; 124 struct v9fs_session_info *v9ses; 125 126 fid = filp->private_data; 127 BUG_ON(fid == NULL); 128 129 BUG_ON((fl->c.flc_flags & FL_POSIX) != FL_POSIX); 130 131 res = locks_lock_file_wait(filp, fl); 132 if (res < 0) 133 goto out; 134 135 /* convert posix lock to p9 tlock args */ 136 memset(&flock, 0, sizeof(flock)); 137 /* map the lock type */ 138 switch (fl->c.flc_type) { 139 case F_RDLCK: 140 flock.type = P9_LOCK_TYPE_RDLCK; 141 break; 142 case F_WRLCK: 143 flock.type = P9_LOCK_TYPE_WRLCK; 144 break; 145 case F_UNLCK: 146 flock.type = P9_LOCK_TYPE_UNLCK; 147 break; 148 } 149 flock.start = fl->fl_start; 150 if (fl->fl_end == OFFSET_MAX) 151 flock.length = 0; 152 else 153 flock.length = fl->fl_end - fl->fl_start + 1; 154 flock.proc_id = fl->c.flc_pid; 155 flock.client_id = fid->clnt->name; 156 if (IS_SETLKW(cmd)) 157 flock.flags = P9_LOCK_FLAGS_BLOCK; 158 159 v9ses = v9fs_inode2v9ses(file_inode(filp)); 160 161 /* 162 * if its a blocked request and we get P9_LOCK_BLOCKED as the status 163 * for lock request, keep on trying 164 */ 165 for (;;) { 166 res = p9_client_lock_dotl(fid, &flock, &status); 167 if (res < 0) 168 goto out_unlock; 169 170 if (status != P9_LOCK_BLOCKED) 171 break; 172 if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) 173 break; 174 if (schedule_timeout_interruptible(v9ses->session_lock_timeout) 175 != 0) 176 break; 177 /* 178 * p9_client_lock_dotl overwrites flock.client_id with the 179 * server message, free and reuse the client name 180 */ 181 if (flock.client_id != fid->clnt->name) { 182 kfree(flock.client_id); 183 flock.client_id = fid->clnt->name; 184 } 185 } 186 187 /* map 9p status to VFS status */ 188 switch (status) { 189 case P9_LOCK_SUCCESS: 190 res = 0; 191 break; 192 case P9_LOCK_BLOCKED: 193 res = -EAGAIN; 194 break; 195 default: 196 WARN_ONCE(1, "unknown lock status code: %d\n", status); 197 fallthrough; 198 case P9_LOCK_ERROR: 199 case P9_LOCK_GRACE: 200 res = -ENOLCK; 201 break; 202 } 203 204 out_unlock: 205 /* 206 * incase server returned error for lock request, revert 207 * it locally 208 */ 209 if (res < 0 && fl->c.flc_type != F_UNLCK) { 210 unsigned char type = fl->c.flc_type; 211 212 fl->c.flc_type = F_UNLCK; 213 /* Even if this fails we want to return the remote error */ 214 locks_lock_file_wait(filp, fl); 215 fl->c.flc_type = type; 216 } 217 if (flock.client_id != fid->clnt->name) 218 kfree(flock.client_id); 219 out: 220 return res; 221 } 222 223 static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) 224 { 225 struct p9_getlock glock; 226 struct p9_fid *fid; 227 int res = 0; 228 229 fid = filp->private_data; 230 BUG_ON(fid == NULL); 231 232 posix_test_lock(filp, fl); 233 /* 234 * if we have a conflicting lock locally, no need to validate 235 * with server 236 */ 237 if (fl->c.flc_type != F_UNLCK) 238 return res; 239 240 /* convert posix lock to p9 tgetlock args */ 241 memset(&glock, 0, sizeof(glock)); 242 glock.type = P9_LOCK_TYPE_UNLCK; 243 glock.start = fl->fl_start; 244 if (fl->fl_end == OFFSET_MAX) 245 glock.length = 0; 246 else 247 glock.length = fl->fl_end - fl->fl_start + 1; 248 glock.proc_id = fl->c.flc_pid; 249 glock.client_id = fid->clnt->name; 250 251 res = p9_client_getlock_dotl(fid, &glock); 252 if (res < 0) 253 goto out; 254 /* map 9p lock type to os lock type */ 255 switch (glock.type) { 256 case P9_LOCK_TYPE_RDLCK: 257 fl->c.flc_type = F_RDLCK; 258 break; 259 case P9_LOCK_TYPE_WRLCK: 260 fl->c.flc_type = F_WRLCK; 261 break; 262 case P9_LOCK_TYPE_UNLCK: 263 fl->c.flc_type = F_UNLCK; 264 break; 265 } 266 if (glock.type != P9_LOCK_TYPE_UNLCK) { 267 fl->fl_start = glock.start; 268 if (glock.length == 0) 269 fl->fl_end = OFFSET_MAX; 270 else 271 fl->fl_end = glock.start + glock.length - 1; 272 fl->c.flc_pid = -glock.proc_id; 273 } 274 out: 275 if (glock.client_id != fid->clnt->name) 276 kfree(glock.client_id); 277 return res; 278 } 279 280 /** 281 * v9fs_file_lock_dotl - lock a file (or directory) 282 * @filp: file to be locked 283 * @cmd: lock command 284 * @fl: file lock structure 285 * 286 */ 287 288 static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl) 289 { 290 struct inode *inode = file_inode(filp); 291 int ret = -ENOLCK; 292 293 p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n", 294 filp, cmd, fl, filp); 295 296 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->c.flc_type != F_UNLCK) { 297 filemap_write_and_wait(inode->i_mapping); 298 invalidate_mapping_pages(&inode->i_data, 0, -1); 299 } 300 301 if (IS_SETLK(cmd) || IS_SETLKW(cmd)) 302 ret = v9fs_file_do_lock(filp, cmd, fl); 303 else if (IS_GETLK(cmd)) 304 ret = v9fs_file_getlock(filp, fl); 305 else 306 ret = -EINVAL; 307 return ret; 308 } 309 310 /** 311 * v9fs_file_flock_dotl - lock a file 312 * @filp: file to be locked 313 * @cmd: lock command 314 * @fl: file lock structure 315 * 316 */ 317 318 static int v9fs_file_flock_dotl(struct file *filp, int cmd, 319 struct file_lock *fl) 320 { 321 struct inode *inode = file_inode(filp); 322 int ret = -ENOLCK; 323 324 p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n", 325 filp, cmd, fl, filp); 326 327 if (!(fl->c.flc_flags & FL_FLOCK)) 328 goto out_err; 329 330 if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->c.flc_type != F_UNLCK) { 331 filemap_write_and_wait(inode->i_mapping); 332 invalidate_mapping_pages(&inode->i_data, 0, -1); 333 } 334 /* Convert flock to posix lock */ 335 fl->c.flc_flags |= FL_POSIX; 336 fl->c.flc_flags ^= FL_FLOCK; 337 338 if (IS_SETLK(cmd) | IS_SETLKW(cmd)) 339 ret = v9fs_file_do_lock(filp, cmd, fl); 340 else 341 ret = -EINVAL; 342 out_err: 343 return ret; 344 } 345 346 /** 347 * v9fs_file_read_iter - read from a file 348 * @iocb: The operation parameters 349 * @to: The buffer to read into 350 * 351 */ 352 static ssize_t 353 v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 354 { 355 struct p9_fid *fid = iocb->ki_filp->private_data; 356 357 p9_debug(P9_DEBUG_VFS, "fid %d count %zu offset %lld\n", 358 fid->fid, iov_iter_count(to), iocb->ki_pos); 359 360 if (fid->mode & P9L_DIRECT) 361 return netfs_unbuffered_read_iter(iocb, to); 362 363 p9_debug(P9_DEBUG_VFS, "(cached)\n"); 364 return netfs_file_read_iter(iocb, to); 365 } 366 367 /* 368 * v9fs_file_splice_read - splice-read from a file 369 * @in: The 9p file to read from 370 * @ppos: Where to find/update the file position 371 * @pipe: The pipe to splice into 372 * @len: The maximum amount of data to splice 373 * @flags: SPLICE_F_* flags 374 */ 375 static ssize_t v9fs_file_splice_read(struct file *in, loff_t *ppos, 376 struct pipe_inode_info *pipe, 377 size_t len, unsigned int flags) 378 { 379 struct p9_fid *fid = in->private_data; 380 381 p9_debug(P9_DEBUG_VFS, "fid %d count %zu offset %lld\n", 382 fid->fid, len, *ppos); 383 384 if (fid->mode & P9L_DIRECT) 385 return copy_splice_read(in, ppos, pipe, len, flags); 386 return filemap_splice_read(in, ppos, pipe, len, flags); 387 } 388 389 /** 390 * v9fs_file_write_iter - write to a file 391 * @iocb: The operation parameters 392 * @from: The data to write 393 * 394 */ 395 static ssize_t 396 v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) 397 { 398 struct file *file = iocb->ki_filp; 399 struct p9_fid *fid = file->private_data; 400 401 p9_debug(P9_DEBUG_VFS, "fid %d\n", fid->fid); 402 403 if (fid->mode & (P9L_DIRECT | P9L_NOWRITECACHE)) 404 return netfs_unbuffered_write_iter(iocb, from); 405 406 p9_debug(P9_DEBUG_CACHE, "(cached)\n"); 407 return netfs_file_write_iter(iocb, from); 408 } 409 410 static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, 411 int datasync) 412 { 413 struct p9_fid *fid; 414 struct inode *inode = filp->f_mapping->host; 415 struct p9_wstat wstat; 416 int retval; 417 418 retval = file_write_and_wait_range(filp, start, end); 419 if (retval) 420 return retval; 421 422 inode_lock(inode); 423 p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); 424 425 fid = filp->private_data; 426 v9fs_blank_wstat(&wstat); 427 428 retval = p9_client_wstat(fid, &wstat); 429 inode_unlock(inode); 430 431 return retval; 432 } 433 434 int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, 435 int datasync) 436 { 437 struct p9_fid *fid; 438 struct inode *inode = filp->f_mapping->host; 439 int retval; 440 441 retval = file_write_and_wait_range(filp, start, end); 442 if (retval) 443 return retval; 444 445 inode_lock(inode); 446 p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); 447 448 fid = filp->private_data; 449 450 retval = p9_client_fsync(fid, datasync); 451 inode_unlock(inode); 452 453 return retval; 454 } 455 456 static int 457 v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma) 458 { 459 int retval; 460 struct inode *inode = file_inode(filp); 461 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); 462 463 p9_debug(P9_DEBUG_MMAP, "filp :%p\n", filp); 464 465 if (!(v9ses->cache & CACHE_WRITEBACK)) { 466 p9_debug(P9_DEBUG_CACHE, "(read-only mmap mode)"); 467 return generic_file_readonly_mmap(filp, vma); 468 } 469 470 retval = generic_file_mmap(filp, vma); 471 if (!retval) 472 vma->vm_ops = &v9fs_mmap_file_vm_ops; 473 474 return retval; 475 } 476 477 static vm_fault_t 478 v9fs_vm_page_mkwrite(struct vm_fault *vmf) 479 { 480 return netfs_page_mkwrite(vmf, NULL); 481 } 482 483 static void v9fs_mmap_vm_close(struct vm_area_struct *vma) 484 { 485 struct inode *inode; 486 487 struct writeback_control wbc = { 488 .nr_to_write = LONG_MAX, 489 .sync_mode = WB_SYNC_ALL, 490 .range_start = (loff_t)vma->vm_pgoff * PAGE_SIZE, 491 /* absolute end, byte at end included */ 492 .range_end = (loff_t)vma->vm_pgoff * PAGE_SIZE + 493 (vma->vm_end - vma->vm_start - 1), 494 }; 495 496 if (!(vma->vm_flags & VM_SHARED)) 497 return; 498 499 p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma); 500 501 inode = file_inode(vma->vm_file); 502 filemap_fdatawrite_wbc(inode->i_mapping, &wbc); 503 } 504 505 static const struct vm_operations_struct v9fs_mmap_file_vm_ops = { 506 .close = v9fs_mmap_vm_close, 507 .fault = filemap_fault, 508 .map_pages = filemap_map_pages, 509 .page_mkwrite = v9fs_vm_page_mkwrite, 510 }; 511 512 const struct file_operations v9fs_file_operations = { 513 .llseek = generic_file_llseek, 514 .read_iter = v9fs_file_read_iter, 515 .write_iter = v9fs_file_write_iter, 516 .open = v9fs_file_open, 517 .release = v9fs_dir_release, 518 .lock = v9fs_file_lock, 519 .mmap = generic_file_readonly_mmap, 520 .splice_read = v9fs_file_splice_read, 521 .splice_write = iter_file_splice_write, 522 .fsync = v9fs_file_fsync, 523 .setlease = simple_nosetlease, 524 }; 525 526 const struct file_operations v9fs_file_operations_dotl = { 527 .llseek = generic_file_llseek, 528 .read_iter = v9fs_file_read_iter, 529 .write_iter = v9fs_file_write_iter, 530 .open = v9fs_file_open, 531 .release = v9fs_dir_release, 532 .lock = v9fs_file_lock_dotl, 533 .flock = v9fs_file_flock_dotl, 534 .mmap = v9fs_file_mmap, 535 .splice_read = v9fs_file_splice_read, 536 .splice_write = iter_file_splice_write, 537 .fsync = v9fs_file_fsync_dotl, 538 .setlease = simple_nosetlease, 539 }; 540
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.