diff options
author | Josef Bacik <josef@redhat.com> | 2011-07-18 13:21:38 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-07-20 20:47:58 -0400 |
commit | 06222e491e663dac939f04b125c9dc52126a75c4 (patch) | |
tree | 99636fd666c8148a5bf58ea4844263d4b3a36310 | |
parent | c334b1138bd44bea578eab7971c59bd9212a1093 (diff) |
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>
-rw-r--r-- | fs/block_dev.c | 11 | ||||
-rw-r--r-- | fs/ceph/dir.c | 8 | ||||
-rw-r--r-- | fs/ceph/file.c | 20 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 7 | ||||
-rw-r--r-- | fs/fuse/file.c | 21 | ||||
-rw-r--r-- | fs/hpfs/dir.c | 4 | ||||
-rw-r--r-- | fs/nfs/file.c | 7 |
7 files changed, 66 insertions, 12 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c index 610e8e0b04b8..966617a422d9 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -355,20 +355,25 @@ static loff_t block_llseek(struct file *file, loff_t offset, int origin) | |||
355 | mutex_lock(&bd_inode->i_mutex); | 355 | mutex_lock(&bd_inode->i_mutex); |
356 | size = i_size_read(bd_inode); | 356 | size = i_size_read(bd_inode); |
357 | 357 | ||
358 | retval = -EINVAL; | ||
358 | switch (origin) { | 359 | switch (origin) { |
359 | case 2: | 360 | case SEEK_END: |
360 | offset += size; | 361 | offset += size; |
361 | break; | 362 | break; |
362 | case 1: | 363 | case SEEK_CUR: |
363 | offset += file->f_pos; | 364 | offset += file->f_pos; |
365 | case SEEK_SET: | ||
366 | break; | ||
367 | default: | ||
368 | goto out; | ||
364 | } | 369 | } |
365 | retval = -EINVAL; | ||
366 | if (offset >= 0 && offset <= size) { | 370 | if (offset >= 0 && offset <= size) { |
367 | if (offset != file->f_pos) { | 371 | if (offset != file->f_pos) { |
368 | file->f_pos = offset; | 372 | file->f_pos = offset; |
369 | } | 373 | } |
370 | retval = offset; | 374 | retval = offset; |
371 | } | 375 | } |
376 | out: | ||
372 | mutex_unlock(&bd_inode->i_mutex); | 377 | mutex_unlock(&bd_inode->i_mutex); |
373 | return retval; | 378 | return retval; |
374 | } | 379 | } |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index e8477dc51b45..0972b457a03f 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -446,14 +446,19 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) | |||
446 | loff_t retval; | 446 | loff_t retval; |
447 | 447 | ||
448 | mutex_lock(&inode->i_mutex); | 448 | mutex_lock(&inode->i_mutex); |
449 | retval = -EINVAL; | ||
449 | switch (origin) { | 450 | switch (origin) { |
450 | case SEEK_END: | 451 | case SEEK_END: |
451 | offset += inode->i_size + 2; /* FIXME */ | 452 | offset += inode->i_size + 2; /* FIXME */ |
452 | break; | 453 | break; |
453 | case SEEK_CUR: | 454 | case SEEK_CUR: |
454 | offset += file->f_pos; | 455 | offset += file->f_pos; |
456 | case SEEK_SET: | ||
457 | break; | ||
458 | default: | ||
459 | goto out; | ||
455 | } | 460 | } |
456 | retval = -EINVAL; | 461 | |
457 | if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { | 462 | if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { |
458 | if (offset != file->f_pos) { | 463 | if (offset != file->f_pos) { |
459 | file->f_pos = offset; | 464 | file->f_pos = offset; |
@@ -477,6 +482,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin) | |||
477 | if (offset > old_offset) | 482 | if (offset > old_offset) |
478 | fi->dir_release_count--; | 483 | fi->dir_release_count--; |
479 | } | 484 | } |
485 | out: | ||
480 | mutex_unlock(&inode->i_mutex); | 486 | mutex_unlock(&inode->i_mutex); |
481 | return retval; | 487 | return retval; |
482 | } | 488 | } |
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) | |||
768 | 768 | ||
769 | mutex_lock(&inode->i_mutex); | 769 | mutex_lock(&inode->i_mutex); |
770 | __ceph_do_pending_vmtruncate(inode); | 770 | __ceph_do_pending_vmtruncate(inode); |
771 | switch (origin) { | 771 | if (origin != SEEK_CUR || origin != SEEK_SET) { |
772 | case SEEK_END: | ||
773 | ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); | 772 | ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE); |
774 | if (ret < 0) { | 773 | if (ret < 0) { |
775 | offset = ret; | 774 | offset = ret; |
776 | goto out; | 775 | goto out; |
777 | } | 776 | } |
777 | } | ||
778 | |||
779 | switch (origin) { | ||
780 | case SEEK_END: | ||
778 | offset += inode->i_size; | 781 | offset += inode->i_size; |
779 | break; | 782 | break; |
780 | case SEEK_CUR: | 783 | case SEEK_CUR: |
@@ -790,6 +793,19 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int origin) | |||
790 | } | 793 | } |
791 | offset += file->f_pos; | 794 | offset += file->f_pos; |
792 | break; | 795 | break; |
796 | case SEEK_DATA: | ||
797 | if (offset >= inode->i_size) { | ||
798 | ret = -ENXIO; | ||
799 | goto out; | ||
800 | } | ||
801 | break; | ||
802 | case SEEK_HOLE: | ||
803 | if (offset >= inode->i_size) { | ||
804 | ret = -ENXIO; | ||
805 | goto out; | ||
806 | } | ||
807 | offset = inode->i_size; | ||
808 | break; | ||
793 | } | 809 | } |
794 | 810 | ||
795 | if (offset < 0 || offset > inode->i_sb->s_maxbytes) { | 811 | if (offset < 0 || offset > inode->i_sb->s_maxbytes) { |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index cbbb55e781d3..865517470967 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -704,8 +704,11 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
704 | 704 | ||
705 | static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | 705 | static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) |
706 | { | 706 | { |
707 | /* origin == SEEK_END => we must revalidate the cached file length */ | 707 | /* |
708 | if (origin == SEEK_END) { | 708 | * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate |
709 | * the cached file length | ||
710 | */ | ||
711 | if (origin != SEEK_SET || origin != SEEK_CUR) { | ||
709 | int rc; | 712 | int rc; |
710 | struct inode *inode = file->f_path.dentry->d_inode; | 713 | struct inode *inode = file->f_path.dentry->d_inode; |
711 | 714 | ||
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 82a66466a24c..73b89df20851 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -1600,15 +1600,32 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin) | |||
1600 | struct inode *inode = file->f_path.dentry->d_inode; | 1600 | struct inode *inode = file->f_path.dentry->d_inode; |
1601 | 1601 | ||
1602 | mutex_lock(&inode->i_mutex); | 1602 | mutex_lock(&inode->i_mutex); |
1603 | switch (origin) { | 1603 | if (origin != SEEK_CUR || origin != SEEK_SET) { |
1604 | case SEEK_END: | ||
1605 | retval = fuse_update_attributes(inode, NULL, file, NULL); | 1604 | retval = fuse_update_attributes(inode, NULL, file, NULL); |
1606 | if (retval) | 1605 | if (retval) |
1607 | goto exit; | 1606 | goto exit; |
1607 | } | ||
1608 | |||
1609 | switch (origin) { | ||
1610 | case SEEK_END: | ||
1608 | offset += i_size_read(inode); | 1611 | offset += i_size_read(inode); |
1609 | break; | 1612 | break; |
1610 | case SEEK_CUR: | 1613 | case SEEK_CUR: |
1611 | offset += file->f_pos; | 1614 | offset += file->f_pos; |
1615 | break; | ||
1616 | case SEEK_DATA: | ||
1617 | if (offset >= i_size_read(inode)) { | ||
1618 | retval = -ENXIO; | ||
1619 | goto exit; | ||
1620 | } | ||
1621 | break; | ||
1622 | case SEEK_HOLE: | ||
1623 | if (offset >= i_size_read(inode)) { | ||
1624 | retval = -ENXIO; | ||
1625 | goto exit; | ||
1626 | } | ||
1627 | offset = i_size_read(inode); | ||
1628 | break; | ||
1612 | } | 1629 | } |
1613 | retval = -EINVAL; | 1630 | retval = -EINVAL; |
1614 | if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { | 1631 | if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) { |
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index f46ae025bfb5..96a8ed91cedd 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c | |||
@@ -29,6 +29,10 @@ static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) | |||
29 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | 29 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); |
30 | struct super_block *s = i->i_sb; | 30 | struct super_block *s = i->i_sb; |
31 | 31 | ||
32 | /* Somebody else will have to figure out what to do here */ | ||
33 | if (whence == SEEK_DATA || whence == SEEK_HOLE) | ||
34 | return -EINVAL; | ||
35 | |||
32 | hpfs_lock(s); | 36 | hpfs_lock(s); |
33 | 37 | ||
34 | /*printk("dir lseek\n");*/ | 38 | /*printk("dir lseek\n");*/ |
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2f093ed16980..2c1705b6acd7 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -187,8 +187,11 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
187 | filp->f_path.dentry->d_name.name, | 187 | filp->f_path.dentry->d_name.name, |
188 | offset, origin); | 188 | offset, origin); |
189 | 189 | ||
190 | /* origin == SEEK_END => we must revalidate the cached file length */ | 190 | /* |
191 | if (origin == SEEK_END) { | 191 | * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate |
192 | * the cached file length | ||
193 | */ | ||
194 | if (origin != SEEK_SET || origin != SEEK_CUR) { | ||
192 | struct inode *inode = filp->f_mapping->host; | 195 | struct inode *inode = filp->f_mapping->host; |
193 | 196 | ||
194 | int retval = nfs_revalidate_file_size(inode, filp); | 197 | int retval = nfs_revalidate_file_size(inode, filp); |