diff options
author | Sunil Mushran <sunil.mushran@oracle.com> | 2011-07-25 17:58:15 -0400 |
---|---|---|
committer | Sunil Mushran <sunil.mushran@oracle.com> | 2011-07-25 17:58:15 -0400 |
commit | 93862d5e1ab875664c6cc95254fc365028a48bb1 (patch) | |
tree | 3299a37486b2265e051a4c641aa7cfbb309a69d6 | |
parent | 5cffff9e29866a3de98c2c25135b3199491f93b0 (diff) |
ocfs2: Implement llseek()
ocfs2 implements its own llseek() to provide the SEEK_HOLE/SEEK_DATA
functionality.
SEEK_HOLE sets the file pointer to the start of either a hole or an unwritten
(preallocated) extent, that is greater than or equal to the supplied offset.
SEEK_DATA sets the file pointer to the start of an allocated extent (not
unwritten) that is greater than or equal to the supplied offset.
If the supplied offset is on a desired region, then the file pointer is set
to it. Offsets greater than or equal to the file size return -ENXIO.
Unwritten (preallocated) extents are considered holes because the file system
treats reads to such regions in the same way as it does to holes.
Signed-off-by: Sunil Mushran <sunil.mushran@oracle.com>
-rw-r--r-- | fs/ocfs2/extent_map.c | 96 | ||||
-rw-r--r-- | fs/ocfs2/extent_map.h | 2 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 55 |
3 files changed, 151 insertions, 2 deletions
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index 23457b491e8c..2f5b92ef0e53 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c | |||
@@ -832,6 +832,102 @@ out: | |||
832 | return ret; | 832 | return ret; |
833 | } | 833 | } |
834 | 834 | ||
835 | int ocfs2_seek_data_hole_offset(struct file *file, loff_t *offset, int origin) | ||
836 | { | ||
837 | struct inode *inode = file->f_mapping->host; | ||
838 | int ret; | ||
839 | unsigned int is_last = 0, is_data = 0; | ||
840 | u16 cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits; | ||
841 | u32 cpos, cend, clen, hole_size; | ||
842 | u64 extoff, extlen; | ||
843 | struct buffer_head *di_bh = NULL; | ||
844 | struct ocfs2_extent_rec rec; | ||
845 | |||
846 | BUG_ON(origin != SEEK_DATA && origin != SEEK_HOLE); | ||
847 | |||
848 | ret = ocfs2_inode_lock(inode, &di_bh, 0); | ||
849 | if (ret) { | ||
850 | mlog_errno(ret); | ||
851 | goto out; | ||
852 | } | ||
853 | |||
854 | down_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
855 | |||
856 | if (*offset >= inode->i_size) { | ||
857 | ret = -ENXIO; | ||
858 | goto out_unlock; | ||
859 | } | ||
860 | |||
861 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { | ||
862 | if (origin == SEEK_HOLE) | ||
863 | *offset = inode->i_size; | ||
864 | goto out_unlock; | ||
865 | } | ||
866 | |||
867 | clen = 0; | ||
868 | cpos = *offset >> cs_bits; | ||
869 | cend = ocfs2_clusters_for_bytes(inode->i_sb, inode->i_size); | ||
870 | |||
871 | while (cpos < cend && !is_last) { | ||
872 | ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, &hole_size, | ||
873 | &rec, &is_last); | ||
874 | if (ret) { | ||
875 | mlog_errno(ret); | ||
876 | goto out_unlock; | ||
877 | } | ||
878 | |||
879 | extoff = cpos; | ||
880 | extoff <<= cs_bits; | ||
881 | |||
882 | if (rec.e_blkno == 0ULL) { | ||
883 | clen = hole_size; | ||
884 | is_data = 0; | ||
885 | } else { | ||
886 | clen = le16_to_cpu(rec.e_leaf_clusters) - | ||
887 | (cpos - le32_to_cpu(rec.e_cpos)); | ||
888 | is_data = (rec.e_flags & OCFS2_EXT_UNWRITTEN) ? 0 : 1; | ||
889 | } | ||
890 | |||
891 | if ((!is_data && origin == SEEK_HOLE) || | ||
892 | (is_data && origin == SEEK_DATA)) { | ||
893 | if (extoff > *offset) | ||
894 | *offset = extoff; | ||
895 | goto out_unlock; | ||
896 | } | ||
897 | |||
898 | if (!is_last) | ||
899 | cpos += clen; | ||
900 | } | ||
901 | |||
902 | if (origin == SEEK_HOLE) { | ||
903 | extoff = cpos; | ||
904 | extoff <<= cs_bits; | ||
905 | extlen = clen; | ||
906 | extlen <<= cs_bits; | ||
907 | |||
908 | if ((extoff + extlen) > inode->i_size) | ||
909 | extlen = inode->i_size - extoff; | ||
910 | extoff += extlen; | ||
911 | if (extoff > *offset) | ||
912 | *offset = extoff; | ||
913 | goto out_unlock; | ||
914 | } | ||
915 | |||
916 | ret = -ENXIO; | ||
917 | |||
918 | out_unlock: | ||
919 | |||
920 | brelse(di_bh); | ||
921 | |||
922 | up_read(&OCFS2_I(inode)->ip_alloc_sem); | ||
923 | |||
924 | ocfs2_inode_unlock(inode, 0); | ||
925 | out: | ||
926 | if (ret && ret != -ENXIO) | ||
927 | ret = -ENXIO; | ||
928 | return ret; | ||
929 | } | ||
930 | |||
835 | int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, | 931 | int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, |
836 | struct buffer_head *bhs[], int flags, | 932 | struct buffer_head *bhs[], int flags, |
837 | int (*validate)(struct super_block *sb, | 933 | int (*validate)(struct super_block *sb, |
diff --git a/fs/ocfs2/extent_map.h b/fs/ocfs2/extent_map.h index e79d41c2c909..67ea57d2fd59 100644 --- a/fs/ocfs2/extent_map.h +++ b/fs/ocfs2/extent_map.h | |||
@@ -53,6 +53,8 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno, | |||
53 | int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 53 | int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
54 | u64 map_start, u64 map_len); | 54 | u64 map_start, u64 map_len); |
55 | 55 | ||
56 | int ocfs2_seek_data_hole_offset(struct file *file, loff_t *offset, int origin); | ||
57 | |||
56 | int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, | 58 | int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, |
57 | u32 *p_cluster, u32 *num_clusters, | 59 | u32 *p_cluster, u32 *num_clusters, |
58 | struct ocfs2_extent_list *el, | 60 | struct ocfs2_extent_list *el, |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 0fc2bd34039d..c0f015e11c28 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -2591,6 +2591,57 @@ bail: | |||
2591 | return ret; | 2591 | return ret; |
2592 | } | 2592 | } |
2593 | 2593 | ||
2594 | /* Refer generic_file_llseek_unlocked() */ | ||
2595 | static loff_t ocfs2_file_llseek(struct file *file, loff_t offset, int origin) | ||
2596 | { | ||
2597 | struct inode *inode = file->f_mapping->host; | ||
2598 | int ret = 0; | ||
2599 | |||
2600 | mutex_lock(&inode->i_mutex); | ||
2601 | |||
2602 | switch (origin) { | ||
2603 | case SEEK_SET: | ||
2604 | break; | ||
2605 | case SEEK_END: | ||
2606 | offset += inode->i_size; | ||
2607 | break; | ||
2608 | case SEEK_CUR: | ||
2609 | if (offset == 0) { | ||
2610 | offset = file->f_pos; | ||
2611 | goto out; | ||
2612 | } | ||
2613 | offset += file->f_pos; | ||
2614 | break; | ||
2615 | case SEEK_DATA: | ||
2616 | case SEEK_HOLE: | ||
2617 | ret = ocfs2_seek_data_hole_offset(file, &offset, origin); | ||
2618 | if (ret) | ||
2619 | goto out; | ||
2620 | break; | ||
2621 | default: | ||
2622 | ret = -EINVAL; | ||
2623 | goto out; | ||
2624 | } | ||
2625 | |||
2626 | if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) | ||
2627 | ret = -EINVAL; | ||
2628 | if (!ret && offset > inode->i_sb->s_maxbytes) | ||
2629 | ret = -EINVAL; | ||
2630 | if (ret) | ||
2631 | goto out; | ||
2632 | |||
2633 | if (offset != file->f_pos) { | ||
2634 | file->f_pos = offset; | ||
2635 | file->f_version = 0; | ||
2636 | } | ||
2637 | |||
2638 | out: | ||
2639 | mutex_unlock(&inode->i_mutex); | ||
2640 | if (ret) | ||
2641 | return ret; | ||
2642 | return offset; | ||
2643 | } | ||
2644 | |||
2594 | const struct inode_operations ocfs2_file_iops = { | 2645 | const struct inode_operations ocfs2_file_iops = { |
2595 | .setattr = ocfs2_setattr, | 2646 | .setattr = ocfs2_setattr, |
2596 | .getattr = ocfs2_getattr, | 2647 | .getattr = ocfs2_getattr, |
@@ -2615,7 +2666,7 @@ const struct inode_operations ocfs2_special_file_iops = { | |||
2615 | * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks! | 2666 | * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks! |
2616 | */ | 2667 | */ |
2617 | const struct file_operations ocfs2_fops = { | 2668 | const struct file_operations ocfs2_fops = { |
2618 | .llseek = generic_file_llseek, | 2669 | .llseek = ocfs2_file_llseek, |
2619 | .read = do_sync_read, | 2670 | .read = do_sync_read, |
2620 | .write = do_sync_write, | 2671 | .write = do_sync_write, |
2621 | .mmap = ocfs2_mmap, | 2672 | .mmap = ocfs2_mmap, |
@@ -2663,7 +2714,7 @@ const struct file_operations ocfs2_dops = { | |||
2663 | * the cluster. | 2714 | * the cluster. |
2664 | */ | 2715 | */ |
2665 | const struct file_operations ocfs2_fops_no_plocks = { | 2716 | const struct file_operations ocfs2_fops_no_plocks = { |
2666 | .llseek = generic_file_llseek, | 2717 | .llseek = ocfs2_file_llseek, |
2667 | .read = do_sync_read, | 2718 | .read = do_sync_read, |
2668 | .write = do_sync_write, | 2719 | .write = do_sync_write, |
2669 | .mmap = ocfs2_mmap, | 2720 | .mmap = ocfs2_mmap, |