Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs

* 'for-linus' of git://oss.sgi.com/xfs/xfs:
xfs: fix getbmap vs mmap deadlock
xfs: a couple getbmap cleanups
xfs: add more checks to superblock validation
xfs_file_last_byte() needs to acquire ilock

+108 -89
+103 -89
fs/xfs/xfs_bmap.c
··· 5880 5880 void *arg) /* formatter arg */ 5881 5881 { 5882 5882 __int64_t bmvend; /* last block requested */ 5883 - int error; /* return value */ 5883 + int error = 0; /* return value */ 5884 5884 __int64_t fixlen; /* length for -1 case */ 5885 5885 int i; /* extent number */ 5886 5886 int lock; /* lock state */ ··· 5890 5890 int nexleft; /* # of user extents left */ 5891 5891 int subnex; /* # of bmapi's can do */ 5892 5892 int nmap; /* number of map entries */ 5893 - struct getbmapx out; /* output structure */ 5893 + struct getbmapx *out; /* output structure */ 5894 5894 int whichfork; /* data or attr fork */ 5895 5895 int prealloced; /* this is a file with 5896 5896 * preallocated data space */ 5897 5897 int iflags; /* interface flags */ 5898 5898 int bmapi_flags; /* flags for xfs_bmapi */ 5899 + int cur_ext = 0; 5899 5900 5900 5901 mp = ip->i_mount; 5901 5902 iflags = bmv->bmv_iflags; 5902 - 5903 5903 whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK; 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 5904 5926 5905 if (whichfork == XFS_ATTR_FORK) { 5927 5906 if (XFS_IFORK_Q(ip)) { ··· 5915 5936 ip->i_mount); 5916 5937 return XFS_ERROR(EFSCORRUPTED); 5917 5938 } 5918 - } else if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && 5919 - ip->i_d.di_format != XFS_DINODE_FMT_BTREE && 5920 - ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) 5921 - return XFS_ERROR(EINVAL); 5922 - if (whichfork == XFS_DATA_FORK) { 5939 + 5940 + prealloced = 0; 5941 + fixlen = 1LL << 32; 5942 + } else { 5943 + /* 5944 + * If the BMV_IF_NO_DMAPI_READ interface bit specified, do 5945 + * not generate a DMAPI read event. Otherwise, if the 5946 + * DM_EVENT_READ bit is set for the file, generate a read 5947 + * event in order that the DMAPI application may do its thing 5948 + * before we return the extents. Usually this means restoring 5949 + * user file data to regions of the file that look like holes. 5950 + * 5951 + * The "old behavior" (from XFS_IOC_GETBMAP) is to not specify 5952 + * BMV_IF_NO_DMAPI_READ so that read events are generated. 5953 + * If this were not true, callers of ioctl(XFS_IOC_GETBMAP) 5954 + * could misinterpret holes in a DMAPI file as true holes, 5955 + * when in fact they may represent offline user data. 5956 + */ 5957 + if (DM_EVENT_ENABLED(ip, DM_EVENT_READ) && 5958 + !(iflags & BMV_IF_NO_DMAPI_READ)) { 5959 + error = XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 5960 + 0, 0, 0, NULL); 5961 + if (error) 5962 + return XFS_ERROR(error); 5963 + } 5964 + 5965 + if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && 5966 + ip->i_d.di_format != XFS_DINODE_FMT_BTREE && 5967 + ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) 5968 + return XFS_ERROR(EINVAL); 5969 + 5923 5970 if (xfs_get_extsz_hint(ip) || 5924 5971 ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ 5925 5972 prealloced = 1; ··· 5954 5949 prealloced = 0; 5955 5950 fixlen = ip->i_size; 5956 5951 } 5957 - } else { 5958 - prealloced = 0; 5959 - fixlen = 1LL << 32; 5960 5952 } 5961 5953 5962 5954 if (bmv->bmv_length == -1) { 5963 5955 fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); 5964 - bmv->bmv_length = MAX( (__int64_t)(fixlen - bmv->bmv_offset), 5965 - (__int64_t)0); 5966 - } else if (bmv->bmv_length < 0) 5967 - return XFS_ERROR(EINVAL); 5968 - if (bmv->bmv_length == 0) { 5956 + bmv->bmv_length = 5957 + max_t(__int64_t, fixlen - bmv->bmv_offset, 0); 5958 + } else if (bmv->bmv_length == 0) { 5969 5959 bmv->bmv_entries = 0; 5970 5960 return 0; 5961 + } else if (bmv->bmv_length < 0) { 5962 + return XFS_ERROR(EINVAL); 5971 5963 } 5964 + 5972 5965 nex = bmv->bmv_count - 1; 5973 5966 if (nex <= 0) 5974 5967 return XFS_ERROR(EINVAL); 5975 5968 bmvend = bmv->bmv_offset + bmv->bmv_length; 5976 5969 5970 + 5971 + if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) 5972 + return XFS_ERROR(ENOMEM); 5973 + out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL); 5974 + if (!out) 5975 + return XFS_ERROR(ENOMEM); 5976 + 5977 5977 xfs_ilock(ip, XFS_IOLOCK_SHARED); 5978 - 5979 - if (((iflags & BMV_IF_DELALLOC) == 0) && 5980 - (whichfork == XFS_DATA_FORK) && 5981 - (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) { 5982 - /* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */ 5983 - error = xfs_flush_pages(ip, (xfs_off_t)0, 5984 - -1, 0, FI_REMAPF); 5985 - if (error) { 5986 - xfs_iunlock(ip, XFS_IOLOCK_SHARED); 5987 - return error; 5978 + if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) { 5979 + if (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size) { 5980 + error = xfs_flush_pages(ip, 0, -1, 0, FI_REMAPF); 5981 + if (error) 5982 + goto out_unlock_iolock; 5988 5983 } 5989 - } 5990 5984 5991 - ASSERT(whichfork == XFS_ATTR_FORK || (iflags & BMV_IF_DELALLOC) || 5992 - ip->i_delayed_blks == 0); 5985 + ASSERT(ip->i_delayed_blks == 0); 5986 + } 5993 5987 5994 5988 lock = xfs_ilock_map_shared(ip); 5995 5989 ··· 5999 5995 if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) 6000 5996 nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; 6001 5997 6002 - bmapi_flags = xfs_bmapi_aflag(whichfork) | 6003 - ((iflags & BMV_IF_PREALLOC) ? 0 : XFS_BMAPI_IGSTATE); 5998 + bmapi_flags = xfs_bmapi_aflag(whichfork); 5999 + if (!(iflags & BMV_IF_PREALLOC)) 6000 + bmapi_flags |= XFS_BMAPI_IGSTATE; 6004 6001 6005 6002 /* 6006 6003 * Allocate enough space to handle "subnex" maps at a time. 6007 6004 */ 6005 + error = ENOMEM; 6008 6006 subnex = 16; 6009 - map = kmem_alloc(subnex * sizeof(*map), KM_SLEEP); 6007 + map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL); 6008 + if (!map) 6009 + goto out_unlock_ilock; 6010 6010 6011 6011 bmv->bmv_entries = 0; 6012 6012 6013 - if ((XFS_IFORK_NEXTENTS(ip, whichfork) == 0)) { 6014 - if (((iflags & BMV_IF_DELALLOC) == 0) || 6015 - whichfork == XFS_ATTR_FORK) { 6016 - error = 0; 6017 - goto unlock_and_return; 6018 - } 6013 + if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0 && 6014 + (whichfork == XFS_ATTR_FORK || !(iflags & BMV_IF_DELALLOC))) { 6015 + error = 0; 6016 + goto out_free_map; 6019 6017 } 6020 6018 6021 6019 nexleft = nex; ··· 6029 6023 bmapi_flags, NULL, 0, map, &nmap, 6030 6024 NULL, NULL); 6031 6025 if (error) 6032 - goto unlock_and_return; 6026 + goto out_free_map; 6033 6027 ASSERT(nmap <= subnex); 6034 6028 6035 6029 for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) { 6036 - out.bmv_oflags = 0; 6030 + out[cur_ext].bmv_oflags = 0; 6037 6031 if (map[i].br_state == XFS_EXT_UNWRITTEN) 6038 - out.bmv_oflags |= BMV_OF_PREALLOC; 6032 + out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; 6039 6033 else if (map[i].br_startblock == DELAYSTARTBLOCK) 6040 - out.bmv_oflags |= BMV_OF_DELALLOC; 6041 - out.bmv_offset = XFS_FSB_TO_BB(mp, map[i].br_startoff); 6042 - out.bmv_length = XFS_FSB_TO_BB(mp, map[i].br_blockcount); 6043 - out.bmv_unused1 = out.bmv_unused2 = 0; 6034 + out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC; 6035 + out[cur_ext].bmv_offset = 6036 + XFS_FSB_TO_BB(mp, map[i].br_startoff); 6037 + out[cur_ext].bmv_length = 6038 + XFS_FSB_TO_BB(mp, map[i].br_blockcount); 6039 + out[cur_ext].bmv_unused1 = 0; 6040 + out[cur_ext].bmv_unused2 = 0; 6044 6041 ASSERT(((iflags & BMV_IF_DELALLOC) != 0) || 6045 6042 (map[i].br_startblock != DELAYSTARTBLOCK)); 6046 6043 if (map[i].br_startblock == HOLESTARTBLOCK && 6047 6044 whichfork == XFS_ATTR_FORK) { 6048 6045 /* came to the end of attribute fork */ 6049 - out.bmv_oflags |= BMV_OF_LAST; 6050 - goto unlock_and_return; 6051 - } else { 6052 - int full = 0; /* user array is full */ 6053 - 6054 - if (!xfs_getbmapx_fix_eof_hole(ip, &out, 6055 - prealloced, bmvend, 6056 - map[i].br_startblock)) { 6057 - goto unlock_and_return; 6058 - } 6059 - 6060 - /* format results & advance arg */ 6061 - error = formatter(&arg, &out, &full); 6062 - if (error || full) 6063 - goto unlock_and_return; 6064 - nexleft--; 6065 - bmv->bmv_offset = 6066 - out.bmv_offset + out.bmv_length; 6067 - bmv->bmv_length = MAX((__int64_t)0, 6068 - (__int64_t)(bmvend - bmv->bmv_offset)); 6069 - bmv->bmv_entries++; 6046 + out[cur_ext].bmv_oflags |= BMV_OF_LAST; 6047 + goto out_free_map; 6070 6048 } 6049 + 6050 + if (!xfs_getbmapx_fix_eof_hole(ip, &out[cur_ext], 6051 + prealloced, bmvend, 6052 + map[i].br_startblock)) 6053 + goto out_free_map; 6054 + 6055 + nexleft--; 6056 + bmv->bmv_offset = 6057 + out[cur_ext].bmv_offset + 6058 + out[cur_ext].bmv_length; 6059 + bmv->bmv_length = 6060 + max_t(__int64_t, 0, bmvend - bmv->bmv_offset); 6061 + bmv->bmv_entries++; 6062 + cur_ext++; 6071 6063 } 6072 6064 } while (nmap && nexleft && bmv->bmv_length); 6073 6065 6074 - unlock_and_return: 6066 + out_free_map: 6067 + kmem_free(map); 6068 + out_unlock_ilock: 6075 6069 xfs_iunlock_map_shared(ip, lock); 6070 + out_unlock_iolock: 6076 6071 xfs_iunlock(ip, XFS_IOLOCK_SHARED); 6077 6072 6078 - kmem_free(map); 6073 + for (i = 0; i < cur_ext; i++) { 6074 + int full = 0; /* user array is full */ 6075 + 6076 + /* format results & advance arg */ 6077 + error = formatter(&arg, &out[i], &full); 6078 + if (error || full) 6079 + break; 6080 + } 6079 6081 6080 6082 return error; 6081 6083 }
+2
fs/xfs/xfs_inode.c
··· 1258 1258 * necessary. 1259 1259 */ 1260 1260 if (ip->i_df.if_flags & XFS_IFEXTENTS) { 1261 + xfs_ilock(ip, XFS_ILOCK_SHARED); 1261 1262 error = xfs_bmap_last_offset(NULL, ip, &last_block, 1262 1263 XFS_DATA_FORK); 1264 + xfs_iunlock(ip, XFS_ILOCK_SHARED); 1263 1265 if (error) { 1264 1266 last_block = 0; 1265 1267 }
+3
fs/xfs/xfs_mount.c
··· 291 291 sbp->sb_sectsize > XFS_MAX_SECTORSIZE || 292 292 sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || 293 293 sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || 294 + sbp->sb_sectsize != (1 << sbp->sb_sectlog) || 294 295 sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || 295 296 sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || 296 297 sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || 297 298 sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || 299 + sbp->sb_blocksize != (1 << sbp->sb_blocklog) || 298 300 sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || 299 301 sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || 300 302 sbp->sb_inodelog < XFS_DINODE_MIN_LOG || 301 303 sbp->sb_inodelog > XFS_DINODE_MAX_LOG || 304 + sbp->sb_inodesize != (1 << sbp->sb_inodelog) || 302 305 (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || 303 306 (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || 304 307 (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) ||