diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 199 |
1 files changed, 83 insertions, 116 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 89042848f9ec..05c698ccb238 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -1161,6 +1161,24 @@ xfs_bmap_extents_to_btree( | |||
1161 | * since the file data needs to get logged so things will stay consistent. | 1161 | * since the file data needs to get logged so things will stay consistent. |
1162 | * (The bmap-level manipulations are ok, though). | 1162 | * (The bmap-level manipulations are ok, though). |
1163 | */ | 1163 | */ |
1164 | void | ||
1165 | xfs_bmap_local_to_extents_empty( | ||
1166 | struct xfs_inode *ip, | ||
1167 | int whichfork) | ||
1168 | { | ||
1169 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); | ||
1170 | |||
1171 | ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); | ||
1172 | ASSERT(ifp->if_bytes == 0); | ||
1173 | ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); | ||
1174 | |||
1175 | xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork); | ||
1176 | ifp->if_flags &= ~XFS_IFINLINE; | ||
1177 | ifp->if_flags |= XFS_IFEXTENTS; | ||
1178 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); | ||
1179 | } | ||
1180 | |||
1181 | |||
1164 | STATIC int /* error */ | 1182 | STATIC int /* error */ |
1165 | xfs_bmap_local_to_extents( | 1183 | xfs_bmap_local_to_extents( |
1166 | xfs_trans_t *tp, /* transaction pointer */ | 1184 | xfs_trans_t *tp, /* transaction pointer */ |
@@ -1174,9 +1192,12 @@ xfs_bmap_local_to_extents( | |||
1174 | struct xfs_inode *ip, | 1192 | struct xfs_inode *ip, |
1175 | struct xfs_ifork *ifp)) | 1193 | struct xfs_ifork *ifp)) |
1176 | { | 1194 | { |
1177 | int error; /* error return value */ | 1195 | int error = 0; |
1178 | int flags; /* logging flags returned */ | 1196 | int flags; /* logging flags returned */ |
1179 | xfs_ifork_t *ifp; /* inode fork pointer */ | 1197 | xfs_ifork_t *ifp; /* inode fork pointer */ |
1198 | xfs_alloc_arg_t args; /* allocation arguments */ | ||
1199 | xfs_buf_t *bp; /* buffer for extent block */ | ||
1200 | xfs_bmbt_rec_host_t *ep; /* extent record pointer */ | ||
1180 | 1201 | ||
1181 | /* | 1202 | /* |
1182 | * We don't want to deal with the case of keeping inode data inline yet. | 1203 | * We don't want to deal with the case of keeping inode data inline yet. |
@@ -1185,68 +1206,65 @@ xfs_bmap_local_to_extents( | |||
1185 | ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK)); | 1206 | ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK)); |
1186 | ifp = XFS_IFORK_PTR(ip, whichfork); | 1207 | ifp = XFS_IFORK_PTR(ip, whichfork); |
1187 | ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); | 1208 | ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); |
1209 | |||
1210 | if (!ifp->if_bytes) { | ||
1211 | xfs_bmap_local_to_extents_empty(ip, whichfork); | ||
1212 | flags = XFS_ILOG_CORE; | ||
1213 | goto done; | ||
1214 | } | ||
1215 | |||
1188 | flags = 0; | 1216 | flags = 0; |
1189 | error = 0; | 1217 | error = 0; |
1190 | if (ifp->if_bytes) { | 1218 | ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == |
1191 | xfs_alloc_arg_t args; /* allocation arguments */ | 1219 | XFS_IFINLINE); |
1192 | xfs_buf_t *bp; /* buffer for extent block */ | 1220 | memset(&args, 0, sizeof(args)); |
1193 | xfs_bmbt_rec_host_t *ep;/* extent record pointer */ | 1221 | args.tp = tp; |
1194 | 1222 | args.mp = ip->i_mount; | |
1195 | ASSERT((ifp->if_flags & | 1223 | args.firstblock = *firstblock; |
1196 | (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); | 1224 | /* |
1197 | memset(&args, 0, sizeof(args)); | 1225 | * Allocate a block. We know we need only one, since the |
1198 | args.tp = tp; | 1226 | * file currently fits in an inode. |
1199 | args.mp = ip->i_mount; | 1227 | */ |
1200 | args.firstblock = *firstblock; | 1228 | if (*firstblock == NULLFSBLOCK) { |
1201 | /* | 1229 | args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); |
1202 | * Allocate a block. We know we need only one, since the | 1230 | args.type = XFS_ALLOCTYPE_START_BNO; |
1203 | * file currently fits in an inode. | ||
1204 | */ | ||
1205 | if (*firstblock == NULLFSBLOCK) { | ||
1206 | args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); | ||
1207 | args.type = XFS_ALLOCTYPE_START_BNO; | ||
1208 | } else { | ||
1209 | args.fsbno = *firstblock; | ||
1210 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | ||
1211 | } | ||
1212 | args.total = total; | ||
1213 | args.minlen = args.maxlen = args.prod = 1; | ||
1214 | error = xfs_alloc_vextent(&args); | ||
1215 | if (error) | ||
1216 | goto done; | ||
1217 | |||
1218 | /* Can't fail, the space was reserved. */ | ||
1219 | ASSERT(args.fsbno != NULLFSBLOCK); | ||
1220 | ASSERT(args.len == 1); | ||
1221 | *firstblock = args.fsbno; | ||
1222 | bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); | ||
1223 | |||
1224 | /* initialise the block and copy the data */ | ||
1225 | init_fn(tp, bp, ip, ifp); | ||
1226 | |||
1227 | /* account for the change in fork size and log everything */ | ||
1228 | xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); | ||
1229 | xfs_bmap_forkoff_reset(args.mp, ip, whichfork); | ||
1230 | xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); | ||
1231 | xfs_iext_add(ifp, 0, 1); | ||
1232 | ep = xfs_iext_get_ext(ifp, 0); | ||
1233 | xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); | ||
1234 | trace_xfs_bmap_post_update(ip, 0, | ||
1235 | whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0, | ||
1236 | _THIS_IP_); | ||
1237 | XFS_IFORK_NEXT_SET(ip, whichfork, 1); | ||
1238 | ip->i_d.di_nblocks = 1; | ||
1239 | xfs_trans_mod_dquot_byino(tp, ip, | ||
1240 | XFS_TRANS_DQ_BCOUNT, 1L); | ||
1241 | flags |= xfs_ilog_fext(whichfork); | ||
1242 | } else { | 1231 | } else { |
1243 | ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); | 1232 | args.fsbno = *firstblock; |
1244 | xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork); | 1233 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
1245 | } | 1234 | } |
1246 | ifp->if_flags &= ~XFS_IFINLINE; | 1235 | args.total = total; |
1247 | ifp->if_flags |= XFS_IFEXTENTS; | 1236 | args.minlen = args.maxlen = args.prod = 1; |
1248 | XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); | 1237 | error = xfs_alloc_vextent(&args); |
1238 | if (error) | ||
1239 | goto done; | ||
1240 | |||
1241 | /* Can't fail, the space was reserved. */ | ||
1242 | ASSERT(args.fsbno != NULLFSBLOCK); | ||
1243 | ASSERT(args.len == 1); | ||
1244 | *firstblock = args.fsbno; | ||
1245 | bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); | ||
1246 | |||
1247 | /* initialise the block and copy the data */ | ||
1248 | init_fn(tp, bp, ip, ifp); | ||
1249 | |||
1250 | /* account for the change in fork size and log everything */ | ||
1251 | xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); | ||
1252 | xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); | ||
1253 | xfs_bmap_local_to_extents_empty(ip, whichfork); | ||
1249 | flags |= XFS_ILOG_CORE; | 1254 | flags |= XFS_ILOG_CORE; |
1255 | |||
1256 | xfs_iext_add(ifp, 0, 1); | ||
1257 | ep = xfs_iext_get_ext(ifp, 0); | ||
1258 | xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); | ||
1259 | trace_xfs_bmap_post_update(ip, 0, | ||
1260 | whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0, | ||
1261 | _THIS_IP_); | ||
1262 | XFS_IFORK_NEXT_SET(ip, whichfork, 1); | ||
1263 | ip->i_d.di_nblocks = 1; | ||
1264 | xfs_trans_mod_dquot_byino(tp, ip, | ||
1265 | XFS_TRANS_DQ_BCOUNT, 1L); | ||
1266 | flags |= xfs_ilog_fext(whichfork); | ||
1267 | |||
1250 | done: | 1268 | done: |
1251 | *logflagsp = flags; | 1269 | *logflagsp = flags; |
1252 | return error; | 1270 | return error; |
@@ -1323,25 +1341,6 @@ xfs_bmap_add_attrfork_extents( | |||
1323 | } | 1341 | } |
1324 | 1342 | ||
1325 | /* | 1343 | /* |
1326 | * Block initialisation function for local to extent format conversion. | ||
1327 | * | ||
1328 | * This shouldn't actually be called by anyone, so make sure debug kernels cause | ||
1329 | * a noticable failure. | ||
1330 | */ | ||
1331 | STATIC void | ||
1332 | xfs_bmap_local_to_extents_init_fn( | ||
1333 | struct xfs_trans *tp, | ||
1334 | struct xfs_buf *bp, | ||
1335 | struct xfs_inode *ip, | ||
1336 | struct xfs_ifork *ifp) | ||
1337 | { | ||
1338 | ASSERT(0); | ||
1339 | bp->b_ops = &xfs_bmbt_buf_ops; | ||
1340 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | ||
1341 | xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF); | ||
1342 | } | ||
1343 | |||
1344 | /* | ||
1345 | * Called from xfs_bmap_add_attrfork to handle local format files. Each | 1344 | * Called from xfs_bmap_add_attrfork to handle local format files. Each |
1346 | * different data fork content type needs a different callout to do the | 1345 | * different data fork content type needs a different callout to do the |
1347 | * conversion. Some are basic and only require special block initialisation | 1346 | * conversion. Some are basic and only require special block initialisation |
@@ -1381,9 +1380,9 @@ xfs_bmap_add_attrfork_local( | |||
1381 | flags, XFS_DATA_FORK, | 1380 | flags, XFS_DATA_FORK, |
1382 | xfs_symlink_local_to_remote); | 1381 | xfs_symlink_local_to_remote); |
1383 | 1382 | ||
1384 | return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, | 1383 | /* should only be called for types that support local format data */ |
1385 | XFS_DATA_FORK, | 1384 | ASSERT(0); |
1386 | xfs_bmap_local_to_extents_init_fn); | 1385 | return EFSCORRUPTED; |
1387 | } | 1386 | } |
1388 | 1387 | ||
1389 | /* | 1388 | /* |
@@ -4907,20 +4906,19 @@ xfs_bmapi_write( | |||
4907 | orig_mval = mval; | 4906 | orig_mval = mval; |
4908 | orig_nmap = *nmap; | 4907 | orig_nmap = *nmap; |
4909 | #endif | 4908 | #endif |
4909 | whichfork = (flags & XFS_BMAPI_ATTRFORK) ? | ||
4910 | XFS_ATTR_FORK : XFS_DATA_FORK; | ||
4910 | 4911 | ||
4911 | ASSERT(*nmap >= 1); | 4912 | ASSERT(*nmap >= 1); |
4912 | ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); | 4913 | ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); |
4913 | ASSERT(!(flags & XFS_BMAPI_IGSTATE)); | 4914 | ASSERT(!(flags & XFS_BMAPI_IGSTATE)); |
4914 | ASSERT(tp != NULL); | 4915 | ASSERT(tp != NULL); |
4915 | ASSERT(len > 0); | 4916 | ASSERT(len > 0); |
4916 | 4917 | ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL); | |
4917 | whichfork = (flags & XFS_BMAPI_ATTRFORK) ? | ||
4918 | XFS_ATTR_FORK : XFS_DATA_FORK; | ||
4919 | 4918 | ||
4920 | if (unlikely(XFS_TEST_ERROR( | 4919 | if (unlikely(XFS_TEST_ERROR( |
4921 | (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && | 4920 | (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && |
4922 | XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && | 4921 | XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), |
4923 | XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL), | ||
4924 | mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { | 4922 | mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { |
4925 | XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp); | 4923 | XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp); |
4926 | return XFS_ERROR(EFSCORRUPTED); | 4924 | return XFS_ERROR(EFSCORRUPTED); |
@@ -4933,37 +4931,6 @@ xfs_bmapi_write( | |||
4933 | 4931 | ||
4934 | XFS_STATS_INC(xs_blk_mapw); | 4932 | XFS_STATS_INC(xs_blk_mapw); |
4935 | 4933 | ||
4936 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { | ||
4937 | /* | ||
4938 | * XXX (dgc): This assumes we are only called for inodes that | ||
4939 | * contain content neutral data in local format. Anything that | ||
4940 | * contains caller-specific data in local format that needs | ||
4941 | * transformation to move to a block format needs to do the | ||
4942 | * conversion to extent format itself. | ||
4943 | * | ||
4944 | * Directory data forks and attribute forks handle this | ||
4945 | * themselves, but with the addition of metadata verifiers every | ||
4946 | * data fork in local format now contains caller specific data | ||
4947 | * and as such conversion through this function is likely to be | ||
4948 | * broken. | ||
4949 | * | ||
4950 | * The only likely user of this branch is for remote symlinks, | ||
4951 | * but we cannot overwrite the data fork contents of the symlink | ||
4952 | * (EEXIST occurs higher up the stack) and so it will never go | ||
4953 | * from local format to extent format here. Hence I don't think | ||
4954 | * this branch is ever executed intentionally and we should | ||
4955 | * consider removing it and asserting that xfs_bmapi_write() | ||
4956 | * cannot be called directly on local format forks. i.e. callers | ||
4957 | * are completely responsible for local to extent format | ||
4958 | * conversion, not xfs_bmapi_write(). | ||
4959 | */ | ||
4960 | error = xfs_bmap_local_to_extents(tp, ip, firstblock, total, | ||
4961 | &bma.logflags, whichfork, | ||
4962 | xfs_bmap_local_to_extents_init_fn); | ||
4963 | if (error) | ||
4964 | goto error0; | ||
4965 | } | ||
4966 | |||
4967 | if (*firstblock == NULLFSBLOCK) { | 4934 | if (*firstblock == NULLFSBLOCK) { |
4968 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) | 4935 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) |
4969 | bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1; | 4936 | bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1; |