diff options
| -rw-r--r-- | fs/fuse/file.c | 73 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
| -rw-r--r-- | include/uapi/linux/fuse.h | 17 |
3 files changed, 84 insertions, 9 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 570ca4053c80..aa03aab6a24f 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
| @@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block) | |||
| 2231 | return err ? 0 : outarg.block; | 2231 | return err ? 0 : outarg.block; |
| 2232 | } | 2232 | } |
| 2233 | 2233 | ||
| 2234 | static loff_t fuse_lseek(struct file *file, loff_t offset, int whence) | ||
| 2235 | { | ||
| 2236 | struct inode *inode = file->f_mapping->host; | ||
| 2237 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
| 2238 | struct fuse_file *ff = file->private_data; | ||
| 2239 | FUSE_ARGS(args); | ||
| 2240 | struct fuse_lseek_in inarg = { | ||
| 2241 | .fh = ff->fh, | ||
| 2242 | .offset = offset, | ||
| 2243 | .whence = whence | ||
| 2244 | }; | ||
| 2245 | struct fuse_lseek_out outarg; | ||
| 2246 | int err; | ||
| 2247 | |||
| 2248 | if (fc->no_lseek) | ||
| 2249 | goto fallback; | ||
| 2250 | |||
| 2251 | args.in.h.opcode = FUSE_LSEEK; | ||
| 2252 | args.in.h.nodeid = ff->nodeid; | ||
| 2253 | args.in.numargs = 1; | ||
| 2254 | args.in.args[0].size = sizeof(inarg); | ||
| 2255 | args.in.args[0].value = &inarg; | ||
| 2256 | args.out.numargs = 1; | ||
| 2257 | args.out.args[0].size = sizeof(outarg); | ||
| 2258 | args.out.args[0].value = &outarg; | ||
| 2259 | err = fuse_simple_request(fc, &args); | ||
| 2260 | if (err) { | ||
| 2261 | if (err == -ENOSYS) { | ||
| 2262 | fc->no_lseek = 1; | ||
| 2263 | goto fallback; | ||
| 2264 | } | ||
| 2265 | return err; | ||
| 2266 | } | ||
| 2267 | |||
| 2268 | return vfs_setpos(file, outarg.offset, inode->i_sb->s_maxbytes); | ||
| 2269 | |||
| 2270 | fallback: | ||
| 2271 | err = fuse_update_attributes(inode, NULL, file, NULL); | ||
| 2272 | if (!err) | ||
| 2273 | return generic_file_llseek(file, offset, whence); | ||
| 2274 | else | ||
| 2275 | return err; | ||
| 2276 | } | ||
| 2277 | |||
| 2234 | static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) | 2278 | static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) |
| 2235 | { | 2279 | { |
| 2236 | loff_t retval; | 2280 | loff_t retval; |
| 2237 | struct inode *inode = file_inode(file); | 2281 | struct inode *inode = file_inode(file); |
| 2238 | 2282 | ||
| 2239 | /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */ | 2283 | switch (whence) { |
| 2240 | if (whence == SEEK_CUR || whence == SEEK_SET) | 2284 | case SEEK_SET: |
| 2241 | return generic_file_llseek(file, offset, whence); | 2285 | case SEEK_CUR: |
| 2242 | 2286 | /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */ | |
| 2243 | mutex_lock(&inode->i_mutex); | ||
| 2244 | retval = fuse_update_attributes(inode, NULL, file, NULL); | ||
| 2245 | if (!retval) | ||
| 2246 | retval = generic_file_llseek(file, offset, whence); | 2287 | retval = generic_file_llseek(file, offset, whence); |
| 2247 | mutex_unlock(&inode->i_mutex); | 2288 | break; |
| 2289 | case SEEK_END: | ||
| 2290 | mutex_lock(&inode->i_mutex); | ||
| 2291 | retval = fuse_update_attributes(inode, NULL, file, NULL); | ||
| 2292 | if (!retval) | ||
| 2293 | retval = generic_file_llseek(file, offset, whence); | ||
| 2294 | mutex_unlock(&inode->i_mutex); | ||
| 2295 | break; | ||
| 2296 | case SEEK_HOLE: | ||
| 2297 | case SEEK_DATA: | ||
| 2298 | mutex_lock(&inode->i_mutex); | ||
| 2299 | retval = fuse_lseek(file, offset, whence); | ||
| 2300 | mutex_unlock(&inode->i_mutex); | ||
| 2301 | break; | ||
| 2302 | default: | ||
| 2303 | retval = -EINVAL; | ||
| 2304 | } | ||
| 2248 | 2305 | ||
| 2249 | return retval; | 2306 | return retval; |
| 2250 | } | 2307 | } |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 405113101db8..ce394b5fe6b4 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -605,6 +605,9 @@ struct fuse_conn { | |||
| 605 | /** Does the filesystem support asynchronous direct-IO submission? */ | 605 | /** Does the filesystem support asynchronous direct-IO submission? */ |
| 606 | unsigned async_dio:1; | 606 | unsigned async_dio:1; |
| 607 | 607 | ||
| 608 | /** Is lseek not implemented by fs? */ | ||
| 609 | unsigned no_lseek:1; | ||
| 610 | |||
| 608 | /** The number of requests waiting for completion */ | 611 | /** The number of requests waiting for completion */ |
| 609 | atomic_t num_waiting; | 612 | atomic_t num_waiting; |
| 610 | 613 | ||
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index c9aca042e61d..5974fae54e12 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h | |||
| @@ -102,6 +102,9 @@ | |||
| 102 | * - add ctime and ctimensec to fuse_setattr_in | 102 | * - add ctime and ctimensec to fuse_setattr_in |
| 103 | * - add FUSE_RENAME2 request | 103 | * - add FUSE_RENAME2 request |
| 104 | * - add FUSE_NO_OPEN_SUPPORT flag | 104 | * - add FUSE_NO_OPEN_SUPPORT flag |
| 105 | * | ||
| 106 | * 7.24 | ||
| 107 | * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support | ||
| 105 | */ | 108 | */ |
| 106 | 109 | ||
| 107 | #ifndef _LINUX_FUSE_H | 110 | #ifndef _LINUX_FUSE_H |
| @@ -137,7 +140,7 @@ | |||
| 137 | #define FUSE_KERNEL_VERSION 7 | 140 | #define FUSE_KERNEL_VERSION 7 |
| 138 | 141 | ||
| 139 | /** Minor version number of this interface */ | 142 | /** Minor version number of this interface */ |
| 140 | #define FUSE_KERNEL_MINOR_VERSION 23 | 143 | #define FUSE_KERNEL_MINOR_VERSION 24 |
| 141 | 144 | ||
| 142 | /** The node ID of the root inode */ | 145 | /** The node ID of the root inode */ |
| 143 | #define FUSE_ROOT_ID 1 | 146 | #define FUSE_ROOT_ID 1 |
| @@ -358,6 +361,7 @@ enum fuse_opcode { | |||
| 358 | FUSE_FALLOCATE = 43, | 361 | FUSE_FALLOCATE = 43, |
| 359 | FUSE_READDIRPLUS = 44, | 362 | FUSE_READDIRPLUS = 44, |
| 360 | FUSE_RENAME2 = 45, | 363 | FUSE_RENAME2 = 45, |
| 364 | FUSE_LSEEK = 46, | ||
| 361 | 365 | ||
| 362 | /* CUSE specific operations */ | 366 | /* CUSE specific operations */ |
| 363 | CUSE_INIT = 4096, | 367 | CUSE_INIT = 4096, |
| @@ -758,4 +762,15 @@ struct fuse_notify_retrieve_in { | |||
| 758 | /* Device ioctls: */ | 762 | /* Device ioctls: */ |
| 759 | #define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) | 763 | #define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) |
| 760 | 764 | ||
| 765 | struct fuse_lseek_in { | ||
| 766 | uint64_t fh; | ||
| 767 | uint64_t offset; | ||
| 768 | uint32_t whence; | ||
| 769 | uint32_t padding; | ||
| 770 | }; | ||
| 771 | |||
| 772 | struct fuse_lseek_out { | ||
| 773 | uint64_t offset; | ||
| 774 | }; | ||
| 775 | |||
| 761 | #endif /* _LINUX_FUSE_H */ | 776 | #endif /* _LINUX_FUSE_H */ |
