diff --git a/kmod/src/data.c b/kmod/src/data.c index 3f557f9e..b6f2d641 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -1295,7 +1295,7 @@ const struct file_operations scoutfs_file_fops = { .aio_write = scoutfs_file_aio_write, .unlocked_ioctl = scoutfs_ioctl, .fsync = scoutfs_file_fsync, - .llseek = generic_file_llseek, + .llseek = scoutfs_file_llseek, }; diff --git a/kmod/src/file.c b/kmod/src/file.c index 5d8e675e..2878d61e 100644 --- a/kmod/src/file.c +++ b/kmod/src/file.c @@ -104,3 +104,41 @@ int scoutfs_permission(struct inode *inode, int mask) return ret; } + +loff_t scoutfs_file_llseek(struct file *file, loff_t offset, int whence) +{ + struct inode *inode = file->f_mapping->host; + struct super_block *sb = inode->i_sb; + struct scoutfs_lock *lock = NULL; + int ret = 0; + + switch (whence) { + case SEEK_END: + case SEEK_DATA: + case SEEK_HOLE: + /* + * These require a lock and inode refresh as they + * reference i_size. + * + * XXX: SEEK_DATA/SEEK_HOLE can search our extent + * items instead of relying on generic_file_llseek() + * trickery. + */ + ret = scoutfs_lock_inode(sb, DLM_LOCK_PR, + SCOUTFS_LKF_REFRESH_INODE, inode, + &lock); + case SEEK_SET: + case SEEK_CUR: + /* No lock required, fall through to the generic helper */ + break; + default: + ret = -EINVAL; + } + + if (ret == 0) + offset = generic_file_llseek(file, offset, whence); + + scoutfs_unlock(sb, lock, DLM_LOCK_PR); + + return ret ? ret : offset; +} diff --git a/kmod/src/file.h b/kmod/src/file.h index 8df0f330..82d86618 100644 --- a/kmod/src/file.h +++ b/kmod/src/file.h @@ -6,5 +6,6 @@ ssize_t scoutfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov, ssize_t scoutfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos); int scoutfs_permission(struct inode *inode, int mask); +loff_t scoutfs_file_llseek(struct file *file, loff_t offset, int whence); #endif /* _SCOUTFS_FILE_H_ */