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