|
@@ -2231,20 +2231,77 @@ static sector_t fuse_bmap(struct address_space *mapping, sector_t block)
|
|
|
return err ? 0 : outarg.block;
|
|
|
}
|
|
|
|
|
|
+static loff_t fuse_lseek(struct file *file, loff_t offset, int whence)
|
|
|
+{
|
|
|
+ struct inode *inode = file->f_mapping->host;
|
|
|
+ struct fuse_conn *fc = get_fuse_conn(inode);
|
|
|
+ struct fuse_file *ff = file->private_data;
|
|
|
+ FUSE_ARGS(args);
|
|
|
+ struct fuse_lseek_in inarg = {
|
|
|
+ .fh = ff->fh,
|
|
|
+ .offset = offset,
|
|
|
+ .whence = whence
|
|
|
+ };
|
|
|
+ struct fuse_lseek_out outarg;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (fc->no_lseek)
|
|
|
+ goto fallback;
|
|
|
+
|
|
|
+ args.in.h.opcode = FUSE_LSEEK;
|
|
|
+ args.in.h.nodeid = ff->nodeid;
|
|
|
+ args.in.numargs = 1;
|
|
|
+ args.in.args[0].size = sizeof(inarg);
|
|
|
+ args.in.args[0].value = &inarg;
|
|
|
+ args.out.numargs = 1;
|
|
|
+ args.out.args[0].size = sizeof(outarg);
|
|
|
+ args.out.args[0].value = &outarg;
|
|
|
+ err = fuse_simple_request(fc, &args);
|
|
|
+ if (err) {
|
|
|
+ if (err == -ENOSYS) {
|
|
|
+ fc->no_lseek = 1;
|
|
|
+ goto fallback;
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ return vfs_setpos(file, outarg.offset, inode->i_sb->s_maxbytes);
|
|
|
+
|
|
|
+fallback:
|
|
|
+ err = fuse_update_attributes(inode, NULL, file, NULL);
|
|
|
+ if (!err)
|
|
|
+ return generic_file_llseek(file, offset, whence);
|
|
|
+ else
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence)
|
|
|
{
|
|
|
loff_t retval;
|
|
|
struct inode *inode = file_inode(file);
|
|
|
|
|
|
- /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
|
|
|
- if (whence == SEEK_CUR || whence == SEEK_SET)
|
|
|
- return generic_file_llseek(file, offset, whence);
|
|
|
-
|
|
|
- mutex_lock(&inode->i_mutex);
|
|
|
- retval = fuse_update_attributes(inode, NULL, file, NULL);
|
|
|
- if (!retval)
|
|
|
+ switch (whence) {
|
|
|
+ case SEEK_SET:
|
|
|
+ case SEEK_CUR:
|
|
|
+ /* No i_mutex protection necessary for SEEK_CUR and SEEK_SET */
|
|
|
retval = generic_file_llseek(file, offset, whence);
|
|
|
- mutex_unlock(&inode->i_mutex);
|
|
|
+ break;
|
|
|
+ case SEEK_END:
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
+ retval = fuse_update_attributes(inode, NULL, file, NULL);
|
|
|
+ if (!retval)
|
|
|
+ retval = generic_file_llseek(file, offset, whence);
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
+ break;
|
|
|
+ case SEEK_HOLE:
|
|
|
+ case SEEK_DATA:
|
|
|
+ mutex_lock(&inode->i_mutex);
|
|
|
+ retval = fuse_lseek(file, offset, whence);
|
|
|
+ mutex_unlock(&inode->i_mutex);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ retval = -EINVAL;
|
|
|
+ }
|
|
|
|
|
|
return retval;
|
|
|
}
|