Commit 93862d5e1ab875664c6cc95254fc365028a48bb1

Authored by Sunil Mushran
1 parent 5cffff9e29

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>

Showing 3 changed files with 151 additions and 2 deletions Side-by-side Diff

fs/ocfs2/extent_map.c
... ... @@ -832,6 +832,102 @@
832 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 931 int ocfs2_read_virt_blocks(struct inode *inode, u64 v_block, int nr,
836 932 struct buffer_head *bhs[], int flags,
837 933 int (*validate)(struct super_block *sb,
fs/ocfs2/extent_map.h
... ... @@ -53,6 +53,8 @@
53 53 int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
54 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 58 int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
57 59 u32 *p_cluster, u32 *num_clusters,
58 60 struct ocfs2_extent_list *el,
... ... @@ -2591,6 +2591,57 @@
2591 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 2645 const struct inode_operations ocfs2_file_iops = {
2595 2646 .setattr = ocfs2_setattr,
2596 2647 .getattr = ocfs2_getattr,
... ... @@ -2615,7 +2666,7 @@
2615 2666 * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks!
2616 2667 */
2617 2668 const struct file_operations ocfs2_fops = {
2618   - .llseek = generic_file_llseek,
  2669 + .llseek = ocfs2_file_llseek,
2619 2670 .read = do_sync_read,
2620 2671 .write = do_sync_write,
2621 2672 .mmap = ocfs2_mmap,
... ... @@ -2663,7 +2714,7 @@
2663 2714 * the cluster.
2664 2715 */
2665 2716 const struct file_operations ocfs2_fops_no_plocks = {
2666   - .llseek = generic_file_llseek,
  2717 + .llseek = ocfs2_file_llseek,
2667 2718 .read = do_sync_read,
2668 2719 .write = do_sync_write,
2669 2720 .mmap = ocfs2_mmap,