diff options
author | Josef Bacik <josef@redhat.com> | 2011-07-18 19:21:38 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-21 02:47:58 +0200 |
commit | 06222e491e663dac939f04b125c9dc52126a75c4 (patch) | |
tree | 99636fd666c8148a5bf58ea4844263d4b3a36310 /fs/ceph/file.c | |
parent | Ext4: handle SEEK_HOLE/SEEK_DATA generically (diff) | |
download | linux-06222e491e663dac939f04b125c9dc52126a75c4.tar.xz linux-06222e491e663dac939f04b125c9dc52126a75c4.zip |
fs: handle SEEK_HOLE/SEEK_DATA properly in all fs's that define their own llseek
This converts everybody to handle SEEK_HOLE/SEEK_DATA properly. In some cases
we just return -EINVAL, in others we do the normal generic thing, and in others
we're simply making sure that the properly due-dilligence is done. For example
in NFS/CIFS we need to make sure the file size is update properly for the
SEEK_HOLE and SEEK_DATA case, but since it calls the generic llseek stuff itself
that is all we have to do. Thanks,
Signed-off-by: Josef Bacik <josef@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r-- | fs/ceph/file.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 0a292459c895..0d0eae05598f 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -768,13 +768,16 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&inode->i_mutex); __ceph_do_pending_vmtruncate(inode); - switch (origin) { - case SEEK_END: + if (origin != SEEK_CUR || origin != SEEK_SET) { ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); if (ret < 0) { offset = ret; goto out; } + } + + switch (origin) { + case SEEK_END: offset += inode->i_size; break; case SEEK_CUR: @@ -790,6 +793,19 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) } offset += file->f_pos; break; + case SEEK_DATA: + if (offset >= inode->i_size) { + ret = -ENXIO; + goto out; + } + break; + case SEEK_HOLE: + if (offset >= inode->i_size) { + ret = -ENXIO; + goto out; + } + offset = inode->i_size; + break; } if (offset < 0 || offset > inode->i_sb->s_maxbytes) { |