| 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(flags: file->f_flags); | 
|---|
| 51 | else | 
|---|
| 52 | omode = v9fs_uflags2omode(uflags: file->f_flags, | 
|---|
| 53 | extended: v9fs_proto_dotu(v9ses)); | 
|---|
| 54 | fid = file->private_data; | 
|---|
| 55 | if (!fid) { | 
|---|
| 56 | fid = v9fs_fid_clone(dentry: file_dentry(file)); | 
|---|
| 57 | if (IS_ERR(ptr: fid)) | 
|---|
| 58 | return PTR_ERR(ptr: 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, mode: 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, mode: omode); | 
|---|
| 68 | fid->mode |= P9L_DIRECT; | 
|---|
| 69 | } | 
|---|
| 70 | } else { | 
|---|
| 71 | err = p9_client_open(fid, mode: 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, offset: 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, s_flags: v9ses->flags, s_cache: v9ses->cache, f_flags: file->f_flags); | 
|---|
| 90 | v9fs_open_fid_add(inode, fid: &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(f: 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(mapping: inode->i_mapping); | 
|---|
| 112 | invalidate_mapping_pages(mapping: &inode->i_data, start: 0, end: -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(s: &flock, c: 0, n: 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(inode: file_inode(f: 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: &flock, status: &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(timeout: 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(objp: 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(objp: 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(s: &glock, c: 0, n: 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, fl: &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(objp: 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(f: 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(mapping: inode->i_mapping); | 
|---|
| 298 | invalidate_mapping_pages(mapping: &inode->i_data, start: 0, end: -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(f: 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(mapping: inode->i_mapping); | 
|---|
| 332 | invalidate_mapping_pages(mapping: &inode->i_data, start: 0, end: -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, iter: to); | 
|---|
| 362 |  | 
|---|
| 363 | p9_debug(P9_DEBUG_VFS, "(cached)\n"); | 
|---|
| 364 | return netfs_file_read_iter(iocb, iter: 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(file: 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: &wstat); | 
|---|
| 427 |  | 
|---|
| 428 | retval = p9_client_wstat(fid, wst: &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(file: 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_prepare(struct vm_area_desc *desc) | 
|---|
| 458 | { | 
|---|
| 459 | int retval; | 
|---|
| 460 | struct file *filp = desc->file; | 
|---|
| 461 | struct inode *inode = file_inode(f: filp); | 
|---|
| 462 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 
|---|
| 463 |  | 
|---|
| 464 | p9_debug(P9_DEBUG_MMAP, "filp :%p\n", filp); | 
|---|
| 465 |  | 
|---|
| 466 | if (!(v9ses->cache & CACHE_WRITEBACK)) { | 
|---|
| 467 | p9_debug(P9_DEBUG_CACHE, "(read-only mmap mode)"); | 
|---|
| 468 | return generic_file_readonly_mmap_prepare(desc); | 
|---|
| 469 | } | 
|---|
| 470 |  | 
|---|
| 471 | retval = generic_file_mmap_prepare(desc); | 
|---|
| 472 | if (!retval) | 
|---|
| 473 | desc->vm_ops = &v9fs_mmap_file_vm_ops; | 
|---|
| 474 |  | 
|---|
| 475 | return retval; | 
|---|
| 476 | } | 
|---|
| 477 |  | 
|---|
| 478 | static vm_fault_t | 
|---|
| 479 | v9fs_vm_page_mkwrite(struct vm_fault *vmf) | 
|---|
| 480 | { | 
|---|
| 481 | return netfs_page_mkwrite(vmf, NULL); | 
|---|
| 482 | } | 
|---|
| 483 |  | 
|---|
| 484 | static void v9fs_mmap_vm_close(struct vm_area_struct *vma) | 
|---|
| 485 | { | 
|---|
| 486 | struct inode *inode; | 
|---|
| 487 |  | 
|---|
| 488 | struct writeback_control wbc = { | 
|---|
| 489 | .nr_to_write = LONG_MAX, | 
|---|
| 490 | .sync_mode = WB_SYNC_ALL, | 
|---|
| 491 | .range_start = (loff_t)vma->vm_pgoff * PAGE_SIZE, | 
|---|
| 492 | /* absolute end, byte at end included */ | 
|---|
| 493 | .range_end = (loff_t)vma->vm_pgoff * PAGE_SIZE + | 
|---|
| 494 | (vma->vm_end - vma->vm_start - 1), | 
|---|
| 495 | }; | 
|---|
| 496 |  | 
|---|
| 497 | if (!(vma->vm_flags & VM_SHARED)) | 
|---|
| 498 | return; | 
|---|
| 499 |  | 
|---|
| 500 | p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma); | 
|---|
| 501 |  | 
|---|
| 502 | inode = file_inode(f: vma->vm_file); | 
|---|
| 503 | filemap_fdatawrite_wbc(mapping: inode->i_mapping, wbc: &wbc); | 
|---|
| 504 | } | 
|---|
| 505 |  | 
|---|
| 506 | static const struct vm_operations_struct v9fs_mmap_file_vm_ops = { | 
|---|
| 507 | .close = v9fs_mmap_vm_close, | 
|---|
| 508 | .fault = filemap_fault, | 
|---|
| 509 | .map_pages = filemap_map_pages, | 
|---|
| 510 | .page_mkwrite = v9fs_vm_page_mkwrite, | 
|---|
| 511 | }; | 
|---|
| 512 |  | 
|---|
| 513 | const struct file_operations v9fs_file_operations = { | 
|---|
| 514 | .llseek = generic_file_llseek, | 
|---|
| 515 | .read_iter = v9fs_file_read_iter, | 
|---|
| 516 | .write_iter = v9fs_file_write_iter, | 
|---|
| 517 | .open = v9fs_file_open, | 
|---|
| 518 | .release = v9fs_dir_release, | 
|---|
| 519 | .lock = v9fs_file_lock, | 
|---|
| 520 | .mmap_prepare = generic_file_readonly_mmap_prepare, | 
|---|
| 521 | .splice_read = v9fs_file_splice_read, | 
|---|
| 522 | .splice_write = iter_file_splice_write, | 
|---|
| 523 | .fsync = v9fs_file_fsync, | 
|---|
| 524 | .setlease = simple_nosetlease, | 
|---|
| 525 | }; | 
|---|
| 526 |  | 
|---|
| 527 | const struct file_operations v9fs_file_operations_dotl = { | 
|---|
| 528 | .llseek = generic_file_llseek, | 
|---|
| 529 | .read_iter = v9fs_file_read_iter, | 
|---|
| 530 | .write_iter = v9fs_file_write_iter, | 
|---|
| 531 | .open = v9fs_file_open, | 
|---|
| 532 | .release = v9fs_dir_release, | 
|---|
| 533 | .lock = v9fs_file_lock_dotl, | 
|---|
| 534 | .flock = v9fs_file_flock_dotl, | 
|---|
| 535 | .mmap_prepare = v9fs_file_mmap_prepare, | 
|---|
| 536 | .splice_read = v9fs_file_splice_read, | 
|---|
| 537 | .splice_write = iter_file_splice_write, | 
|---|
| 538 | .fsync = v9fs_file_fsync_dotl, | 
|---|
| 539 | .setlease = simple_nosetlease, | 
|---|
| 540 | }; | 
|---|
| 541 |  | 
|---|