aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunil Mushran <sunil.mushran@oracle.com>2011-07-25 17:58:15 -0400
committerSunil Mushran <sunil.mushran@oracle.com>2011-07-25 17:58:15 -0400
commit93862d5e1ab875664c6cc95254fc365028a48bb1 (patch)
tree3299a37486b2265e051a4c641aa7cfbb309a69d6
parent5cffff9e29866a3de98c2c25135b3199491f93b0 (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.c96
-rw-r--r--fs/ocfs2/extent_map.h2
-rw-r--r--fs/ocfs2/file.c55
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
835int 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
918out_unlock:
919
920 brelse(di_bh);
921
922 up_read(&OCFS2_I(inode)->ip_alloc_sem);
923
924 ocfs2_inode_unlock(inode, 0);
925out:
926 if (ret && ret != -ENXIO)
927 ret = -ENXIO;
928 return ret;
929}
930
835int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr, 931int 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,
53int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 53int 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
56int ocfs2_seek_data_hole_offset(struct file *file, loff_t *offset, int origin);
57
56int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, 58int 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() */
2595static 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
2638out:
2639 mutex_unlock(&inode->i_mutex);
2640 if (ret)
2641 return ret;
2642 return offset;
2643}
2644
2594const struct inode_operations ocfs2_file_iops = { 2645const 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 */
2617const struct file_operations ocfs2_fops = { 2668const 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 */
2665const struct file_operations ocfs2_fops_no_plocks = { 2716const 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,