diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 192 |
1 files changed, 103 insertions, 89 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 3a6ed426327a..ca7c6005a487 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -5880,7 +5880,7 @@ xfs_getbmap( | |||
5880 | void *arg) /* formatter arg */ | 5880 | void *arg) /* formatter arg */ |
5881 | { | 5881 | { |
5882 | __int64_t bmvend; /* last block requested */ | 5882 | __int64_t bmvend; /* last block requested */ |
5883 | int error; /* return value */ | 5883 | int error = 0; /* return value */ |
5884 | __int64_t fixlen; /* length for -1 case */ | 5884 | __int64_t fixlen; /* length for -1 case */ |
5885 | int i; /* extent number */ | 5885 | int i; /* extent number */ |
5886 | int lock; /* lock state */ | 5886 | int lock; /* lock state */ |
@@ -5890,39 +5890,18 @@ xfs_getbmap( | |||
5890 | int nexleft; /* # of user extents left */ | 5890 | int nexleft; /* # of user extents left */ |
5891 | int subnex; /* # of bmapi's can do */ | 5891 | int subnex; /* # of bmapi's can do */ |
5892 | int nmap; /* number of map entries */ | 5892 | int nmap; /* number of map entries */ |
5893 | struct getbmapx out; /* output structure */ | 5893 | struct getbmapx *out; /* output structure */ |
5894 | int whichfork; /* data or attr fork */ | 5894 | int whichfork; /* data or attr fork */ |
5895 | int prealloced; /* this is a file with | 5895 | int prealloced; /* this is a file with |
5896 | * preallocated data space */ | 5896 | * preallocated data space */ |
5897 | int iflags; /* interface flags */ | 5897 | int iflags; /* interface flags */ |
5898 | int bmapi_flags; /* flags for xfs_bmapi */ | 5898 | int bmapi_flags; /* flags for xfs_bmapi */ |
5899 | int cur_ext = 0; | ||
5899 | 5900 | ||
5900 | mp = ip->i_mount; | 5901 | mp = ip->i_mount; |
5901 | iflags = bmv->bmv_iflags; | 5902 | iflags = bmv->bmv_iflags; |
5902 | |||
5903 | whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; | 5903 | whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; |
5904 | 5904 | ||
5905 | /* If the BMV_IF_NO_DMAPI_READ interface bit specified, do not | ||
5906 | * generate a DMAPI read event. Otherwise, if the DM_EVENT_READ | ||
5907 | * bit is set for the file, generate a read event in order | ||
5908 | * that the DMAPI application may do its thing before we return | ||
5909 | * the extents. Usually this means restoring user file data to | ||
5910 | * regions of the file that look like holes. | ||
5911 | * | ||
5912 | * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify | ||
5913 | * BMV_IF_NO_DMAPI_READ so that read events are generated. | ||
5914 | * If this were not true, callers of ioctl( XFS_IOC_GETBMAP ) | ||
5915 | * could misinterpret holes in a DMAPI file as true holes, | ||
5916 | * when in fact they may represent offline user data. | ||
5917 | */ | ||
5918 | if ((iflags & BMV_IF_NO_DMAPI_READ) == 0 && | ||
5919 | DM_EVENT_ENABLED(ip, DM_EVENT_READ) && | ||
5920 | whichfork == XFS_DATA_FORK) { | ||
5921 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL); | ||
5922 | if (error) | ||
5923 | return XFS_ERROR(error); | ||
5924 | } | ||
5925 | |||
5926 | if (whichfork == XFS_ATTR_FORK) { | 5905 | if (whichfork == XFS_ATTR_FORK) { |
5927 | if (XFS_IFORK_Q(ip)) { | 5906 | if (XFS_IFORK_Q(ip)) { |
5928 | if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && | 5907 | if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && |
@@ -5936,11 +5915,37 @@ xfs_getbmap( | |||
5936 | ip->i_mount); | 5915 | ip->i_mount); |
5937 | return XFS_ERROR(EFSCORRUPTED); | 5916 | return XFS_ERROR(EFSCORRUPTED); |
5938 | } | 5917 | } |
5939 | } else if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && | 5918 | |
5940 | ip->i_d.di_format != XFS_DINODE_FMT_BTREE && | 5919 | prealloced = 0; |
5941 | ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) | 5920 | fixlen = 1LL << 32; |
5942 | return XFS_ERROR(EINVAL); | 5921 | } else { |
5943 | if (whichfork == XFS_DATA_FORK) { | 5922 | /* |
5923 | * If the BMV_IF_NO_DMAPI_READ interface bit specified, do | ||
5924 | * not generate a DMAPI read event. Otherwise, if the | ||
5925 | * DM_EVENT_READ bit is set for the file, generate a read | ||
5926 | * event in order that the DMAPI application may do its thing | ||
5927 | * before we return the extents. Usually this means restoring | ||
5928 | * user file data to regions of the file that look like holes. | ||
5929 | * | ||
5930 | * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify | ||
5931 | * BMV_IF_NO_DMAPI_READ so that read events are generated. | ||
5932 | * If this were not true, callers of ioctl(XFS_IOC_GETBMAP) | ||
5933 | * could misinterpret holes in a DMAPI file as true holes, | ||
5934 | * when in fact they may represent offline user data. | ||
5935 | */ | ||
5936 | if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && | ||
5937 | !(iflags & BMV_IF_NO_DMAPI_READ)) { | ||
5938 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, | ||
5939 | 0, 0, 0, NULL); | ||
5940 | if (error) | ||
5941 | return XFS_ERROR(error); | ||
5942 | } | ||
5943 | |||
5944 | if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && | ||
5945 | ip->i_d.di_format != XFS_DINODE_FMT_BTREE && | ||
5946 | ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) | ||
5947 | return XFS_ERROR(EINVAL); | ||
5948 | |||
5944 | if (xfs_get_extsz_hint(ip) || | 5949 | if (xfs_get_extsz_hint(ip) || |
5945 | ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ | 5950 | ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ |
5946 | prealloced = 1; | 5951 | prealloced = 1; |
@@ -5949,42 +5954,41 @@ xfs_getbmap( | |||
5949 | prealloced = 0; | 5954 | prealloced = 0; |
5950 | fixlen = ip->i_size; | 5955 | fixlen = ip->i_size; |
5951 | } | 5956 | } |
5952 | } else { | ||
5953 | prealloced = 0; | ||
5954 | fixlen = 1LL << 32; | ||
5955 | } | 5957 | } |
5956 | 5958 | ||
5957 | if (bmv->bmv_length == -1) { | 5959 | if (bmv->bmv_length == -1) { |
5958 | fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); | 5960 | fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); |
5959 | bmv->bmv_length = MAX( (__int64_t)(fixlen - bmv->bmv_offset), | 5961 | bmv->bmv_length = |
5960 | (__int64_t)0); | 5962 | max_t(__int64_t, fixlen - bmv->bmv_offset, 0); |
5961 | } else if (bmv->bmv_length < 0) | 5963 | } else if (bmv->bmv_length == 0) { |
5962 | return XFS_ERROR(EINVAL); | ||
5963 | if (bmv->bmv_length == 0) { | ||
5964 | bmv->bmv_entries = 0; | 5964 | bmv->bmv_entries = 0; |
5965 | return 0; | 5965 | return 0; |
5966 | } else if (bmv->bmv_length < 0) { | ||
5967 | return XFS_ERROR(EINVAL); | ||
5966 | } | 5968 | } |
5969 | |||
5967 | nex = bmv->bmv_count - 1; | 5970 | nex = bmv->bmv_count - 1; |
5968 | if (nex <= 0) | 5971 | if (nex <= 0) |
5969 | return XFS_ERROR(EINVAL); | 5972 | return XFS_ERROR(EINVAL); |
5970 | bmvend = bmv->bmv_offset + bmv->bmv_length; | 5973 | bmvend = bmv->bmv_offset + bmv->bmv_length; |
5971 | 5974 | ||
5972 | xfs_ilock(ip, XFS_IOLOCK_SHARED); | ||
5973 | 5975 | ||
5974 | if (((iflags & BMV_IF_DELALLOC) == 0) && | 5976 | if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) |
5975 | (whichfork == XFS_DATA_FORK) && | 5977 | return XFS_ERROR(ENOMEM); |
5976 | (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) { | 5978 | out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL); |
5977 | /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */ | 5979 | if (!out) |
5978 | error = xfs_flush_pages(ip, (xfs_off_t)0, | 5980 | return XFS_ERROR(ENOMEM); |
5979 | -1, 0, FI_REMAPF); | 5981 | |
5980 | if (error) { | 5982 | xfs_ilock(ip, XFS_IOLOCK_SHARED); |
5981 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 5983 | if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) { |
5982 | return error; | 5984 | if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) { |
5985 | error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF); | ||
5986 | if (error) | ||
5987 | goto out_unlock_iolock; | ||
5983 | } | 5988 | } |
5984 | } | ||
5985 | 5989 | ||
5986 | ASSERT(whichfork == XFS_ATTR_FORK || (iflags & BMV_IF_DELALLOC) || | 5990 | ASSERT(ip->i_delayed_blks == 0); |
5987 | ip->i_delayed_blks == 0); | 5991 | } |
5988 | 5992 | ||
5989 | lock = xfs_ilock_map_shared(ip); | 5993 | lock = xfs_ilock_map_shared(ip); |
5990 | 5994 | ||
@@ -5995,23 +5999,25 @@ xfs_getbmap( | |||
5995 | if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) | 5999 | if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) |
5996 | nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; | 6000 | nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; |
5997 | 6001 | ||
5998 | bmapi_flags = xfs_bmapi_aflag(whichfork) | | 6002 | bmapi_flags = xfs_bmapi_aflag(whichfork); |
5999 | ((iflags & BMV_IF_PREALLOC) ? 0 : XFS_BMAPI_IGSTATE); | 6003 | if (!(iflags & BMV_IF_PREALLOC)) |
6004 | bmapi_flags |= XFS_BMAPI_IGSTATE; | ||
6000 | 6005 | ||
6001 | /* | 6006 | /* |
6002 | * Allocate enough space to handle "subnex" maps at a time. | 6007 | * Allocate enough space to handle "subnex" maps at a time. |
6003 | */ | 6008 | */ |
6009 | error = ENOMEM; | ||
6004 | subnex = 16; | 6010 | subnex = 16; |
6005 | map = kmem_alloc(subnex * sizeof(*map), KM_SLEEP); | 6011 | map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL); |
6012 | if (!map) | ||
6013 | goto out_unlock_ilock; | ||
6006 | 6014 | ||
6007 | bmv->bmv_entries = 0; | 6015 | bmv->bmv_entries = 0; |
6008 | 6016 | ||
6009 | if ((XFS_IFORK_NEXTENTS(ip, whichfork) == 0)) { | 6017 | if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0 && |
6010 | if (((iflags & BMV_IF_DELALLOC) == 0) || | 6018 | (whichfork == XFS_ATTR_FORK || !(iflags & BMV_IF_DELALLOC))) { |
6011 | whichfork == XFS_ATTR_FORK) { | 6019 | error = 0; |
6012 | error = 0; | 6020 | goto out_free_map; |
6013 | goto unlock_and_return; | ||
6014 | } | ||
6015 | } | 6021 | } |
6016 | 6022 | ||
6017 | nexleft = nex; | 6023 | nexleft = nex; |
@@ -6023,53 +6029,61 @@ xfs_getbmap( | |||
6023 | bmapi_flags, NULL, 0, map, &nmap, | 6029 | bmapi_flags, NULL, 0, map, &nmap, |
6024 | NULL, NULL); | 6030 | NULL, NULL); |
6025 | if (error) | 6031 | if (error) |
6026 | goto unlock_and_return; | 6032 | goto out_free_map; |
6027 | ASSERT(nmap <= subnex); | 6033 | ASSERT(nmap <= subnex); |
6028 | 6034 | ||
6029 | for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { | 6035 | for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { |
6030 | out.bmv_oflags = 0; | 6036 | out[cur_ext].bmv_oflags = 0; |
6031 | if (map[i].br_state == XFS_EXT_UNWRITTEN) | 6037 | if (map[i].br_state == XFS_EXT_UNWRITTEN) |
6032 | out.bmv_oflags |= BMV_OF_PREALLOC; | 6038 | out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; |
6033 | else if (map[i].br_startblock == DELAYSTARTBLOCK) | 6039 | else if (map[i].br_startblock == DELAYSTARTBLOCK) |
6034 | out.bmv_oflags |= BMV_OF_DELALLOC; | 6040 | out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC; |
6035 | out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff); | 6041 | out[cur_ext].bmv_offset = |
6036 | out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); | 6042 | XFS_FSB_TO_BB(mp, map[i].br_startoff); |
6037 | out.bmv_unused1 = out.bmv_unused2 = 0; | 6043 | out[cur_ext].bmv_length = |
6044 | XFS_FSB_TO_BB(mp, map[i].br_blockcount); | ||
6045 | out[cur_ext].bmv_unused1 = 0; | ||
6046 | out[cur_ext].bmv_unused2 = 0; | ||
6038 | ASSERT(((iflags & BMV_IF_DELALLOC) != 0) || | 6047 | ASSERT(((iflags & BMV_IF_DELALLOC) != 0) || |
6039 | (map[i].br_startblock != DELAYSTARTBLOCK)); | 6048 | (map[i].br_startblock != DELAYSTARTBLOCK)); |
6040 | if (map[i].br_startblock == HOLESTARTBLOCK && | 6049 | if (map[i].br_startblock == HOLESTARTBLOCK && |
6041 | whichfork == XFS_ATTR_FORK) { | 6050 | whichfork == XFS_ATTR_FORK) { |
6042 | /* came to the end of attribute fork */ | 6051 | /* came to the end of attribute fork */ |
6043 | out.bmv_oflags |= BMV_OF_LAST; | 6052 | out[cur_ext].bmv_oflags |= BMV_OF_LAST; |
6044 | goto unlock_and_return; | 6053 | goto out_free_map; |
6045 | } else { | ||
6046 | int full = 0; /* user array is full */ | ||
6047 | |||
6048 | if (!xfs_getbmapx_fix_eof_hole(ip, &out, | ||
6049 | prealloced, bmvend, | ||
6050 | map[i].br_startblock)) { | ||
6051 | goto unlock_and_return; | ||
6052 | } | ||
6053 | |||
6054 | /* format results & advance arg */ | ||
6055 | error = formatter(&arg, &out, &full); | ||
6056 | if (error || full) | ||
6057 | goto unlock_and_return; | ||
6058 | nexleft--; | ||
6059 | bmv->bmv_offset = | ||
6060 | out.bmv_offset + out.bmv_length; | ||
6061 | bmv->bmv_length = MAX((__int64_t)0, | ||
6062 | (__int64_t)(bmvend - bmv->bmv_offset)); | ||
6063 | bmv->bmv_entries++; | ||
6064 | } | 6054 | } |
6055 | |||
6056 | if (!xfs_getbmapx_fix_eof_hole(ip, &out[cur_ext], | ||
6057 | prealloced, bmvend, | ||
6058 | map[i].br_startblock)) | ||
6059 | goto out_free_map; | ||
6060 | |||
6061 | nexleft--; | ||
6062 | bmv->bmv_offset = | ||
6063 | out[cur_ext].bmv_offset + | ||
6064 | out[cur_ext].bmv_length; | ||
6065 | bmv->bmv_length = | ||
6066 | max_t(__int64_t, 0, bmvend - bmv->bmv_offset); | ||
6067 | bmv->bmv_entries++; | ||
6068 | cur_ext++; | ||
6065 | } | 6069 | } |
6066 | } while (nmap && nexleft && bmv->bmv_length); | 6070 | } while (nmap && nexleft && bmv->bmv_length); |
6067 | 6071 | ||
6068 | unlock_and_return: | 6072 | out_free_map: |
6073 | kmem_free(map); | ||
6074 | out_unlock_ilock: | ||
6069 | xfs_iunlock_map_shared(ip, lock); | 6075 | xfs_iunlock_map_shared(ip, lock); |
6076 | out_unlock_iolock: | ||
6070 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 6077 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
6071 | 6078 | ||
6072 | kmem_free(map); | 6079 | for (i = 0; i < cur_ext; i++) { |
6080 | int full = 0; /* user array is full */ | ||
6081 | |||
6082 | /* format results & advance arg */ | ||
6083 | error = formatter(&arg, &out[i], &full); | ||
6084 | if (error || full) | ||
6085 | break; | ||
6086 | } | ||
6073 | 6087 | ||
6074 | return error; | 6088 | return error; |
6075 | } | 6089 | } |