diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 124 |
1 files changed, 96 insertions, 28 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 0e92d12765d2..b44af9211bd9 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c | |||
@@ -147,7 +147,10 @@ xfs_bmap_local_to_extents( | |||
147 | xfs_fsblock_t *firstblock, /* first block allocated in xaction */ | 147 | xfs_fsblock_t *firstblock, /* first block allocated in xaction */ |
148 | xfs_extlen_t total, /* total blocks needed by transaction */ | 148 | xfs_extlen_t total, /* total blocks needed by transaction */ |
149 | int *logflagsp, /* inode logging flags */ | 149 | int *logflagsp, /* inode logging flags */ |
150 | int whichfork); /* data or attr fork */ | 150 | int whichfork, /* data or attr fork */ |
151 | void (*init_fn)(struct xfs_buf *bp, | ||
152 | struct xfs_inode *ip, | ||
153 | struct xfs_ifork *ifp)); | ||
151 | 154 | ||
152 | /* | 155 | /* |
153 | * Search the extents list for the inode, for the extent containing bno. | 156 | * Search the extents list for the inode, for the extent containing bno. |
@@ -357,7 +360,42 @@ xfs_bmap_add_attrfork_extents( | |||
357 | } | 360 | } |
358 | 361 | ||
359 | /* | 362 | /* |
360 | * Called from xfs_bmap_add_attrfork to handle local format files. | 363 | * Block initialisation functions for local to extent format conversion. |
364 | * As these get more complex, they will be moved to the relevant files, | ||
365 | * but for now they are too simple to worry about. | ||
366 | */ | ||
367 | STATIC void | ||
368 | xfs_bmap_local_to_extents_init_fn( | ||
369 | struct xfs_buf *bp, | ||
370 | struct xfs_inode *ip, | ||
371 | struct xfs_ifork *ifp) | ||
372 | { | ||
373 | bp->b_ops = &xfs_bmbt_buf_ops; | ||
374 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | ||
375 | } | ||
376 | |||
377 | STATIC void | ||
378 | xfs_symlink_local_to_remote( | ||
379 | struct xfs_buf *bp, | ||
380 | struct xfs_inode *ip, | ||
381 | struct xfs_ifork *ifp) | ||
382 | { | ||
383 | /* remote symlink blocks are not verifiable until CRCs come along */ | ||
384 | bp->b_ops = NULL; | ||
385 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Called from xfs_bmap_add_attrfork to handle local format files. Each | ||
390 | * different data fork content type needs a different callout to do the | ||
391 | * conversion. Some are basic and only require special block initialisation | ||
392 | * callouts for the data formating, others (directories) are so specialised they | ||
393 | * handle everything themselves. | ||
394 | * | ||
395 | * XXX (dgc): investigate whether directory conversion can use the generic | ||
396 | * formatting callout. It should be possible - it's just a very complex | ||
397 | * formatter. it would also require passing the transaction through to the init | ||
398 | * function. | ||
361 | */ | 399 | */ |
362 | STATIC int /* error */ | 400 | STATIC int /* error */ |
363 | xfs_bmap_add_attrfork_local( | 401 | xfs_bmap_add_attrfork_local( |
@@ -368,25 +406,29 @@ xfs_bmap_add_attrfork_local( | |||
368 | int *flags) /* inode logging flags */ | 406 | int *flags) /* inode logging flags */ |
369 | { | 407 | { |
370 | xfs_da_args_t dargs; /* args for dir/attr code */ | 408 | xfs_da_args_t dargs; /* args for dir/attr code */ |
371 | int error; /* error return value */ | ||
372 | xfs_mount_t *mp; /* mount structure pointer */ | ||
373 | 409 | ||
374 | if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) | 410 | if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) |
375 | return 0; | 411 | return 0; |
412 | |||
376 | if (S_ISDIR(ip->i_d.di_mode)) { | 413 | if (S_ISDIR(ip->i_d.di_mode)) { |
377 | mp = ip->i_mount; | ||
378 | memset(&dargs, 0, sizeof(dargs)); | 414 | memset(&dargs, 0, sizeof(dargs)); |
379 | dargs.dp = ip; | 415 | dargs.dp = ip; |
380 | dargs.firstblock = firstblock; | 416 | dargs.firstblock = firstblock; |
381 | dargs.flist = flist; | 417 | dargs.flist = flist; |
382 | dargs.total = mp->m_dirblkfsbs; | 418 | dargs.total = ip->i_mount->m_dirblkfsbs; |
383 | dargs.whichfork = XFS_DATA_FORK; | 419 | dargs.whichfork = XFS_DATA_FORK; |
384 | dargs.trans = tp; | 420 | dargs.trans = tp; |
385 | error = xfs_dir2_sf_to_block(&dargs); | 421 | return xfs_dir2_sf_to_block(&dargs); |
386 | } else | 422 | } |
387 | error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, | 423 | |
388 | XFS_DATA_FORK); | 424 | if (S_ISLNK(ip->i_d.di_mode)) |
389 | return error; | 425 | return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, |
426 | flags, XFS_DATA_FORK, | ||
427 | xfs_symlink_local_to_remote); | ||
428 | |||
429 | return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, | ||
430 | XFS_DATA_FORK, | ||
431 | xfs_bmap_local_to_extents_init_fn); | ||
390 | } | 432 | } |
391 | 433 | ||
392 | /* | 434 | /* |
@@ -3099,8 +3141,6 @@ xfs_bmap_extents_to_btree( | |||
3099 | args.fsbno = *firstblock; | 3141 | args.fsbno = *firstblock; |
3100 | } | 3142 | } |
3101 | args.minlen = args.maxlen = args.prod = 1; | 3143 | args.minlen = args.maxlen = args.prod = 1; |
3102 | args.total = args.minleft = args.alignment = args.mod = args.isfl = | ||
3103 | args.minalignslop = 0; | ||
3104 | args.wasdel = wasdel; | 3144 | args.wasdel = wasdel; |
3105 | *logflagsp = 0; | 3145 | *logflagsp = 0; |
3106 | if ((error = xfs_alloc_vextent(&args))) { | 3146 | if ((error = xfs_alloc_vextent(&args))) { |
@@ -3221,7 +3261,10 @@ xfs_bmap_local_to_extents( | |||
3221 | xfs_fsblock_t *firstblock, /* first block allocated in xaction */ | 3261 | xfs_fsblock_t *firstblock, /* first block allocated in xaction */ |
3222 | xfs_extlen_t total, /* total blocks needed by transaction */ | 3262 | xfs_extlen_t total, /* total blocks needed by transaction */ |
3223 | int *logflagsp, /* inode logging flags */ | 3263 | int *logflagsp, /* inode logging flags */ |
3224 | int whichfork) /* data or attr fork */ | 3264 | int whichfork, |
3265 | void (*init_fn)(struct xfs_buf *bp, | ||
3266 | struct xfs_inode *ip, | ||
3267 | struct xfs_ifork *ifp)) | ||
3225 | { | 3268 | { |
3226 | int error; /* error return value */ | 3269 | int error; /* error return value */ |
3227 | int flags; /* logging flags returned */ | 3270 | int flags; /* logging flags returned */ |
@@ -3241,12 +3284,12 @@ xfs_bmap_local_to_extents( | |||
3241 | xfs_buf_t *bp; /* buffer for extent block */ | 3284 | xfs_buf_t *bp; /* buffer for extent block */ |
3242 | xfs_bmbt_rec_host_t *ep;/* extent record pointer */ | 3285 | xfs_bmbt_rec_host_t *ep;/* extent record pointer */ |
3243 | 3286 | ||
3287 | ASSERT((ifp->if_flags & | ||
3288 | (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); | ||
3244 | memset(&args, 0, sizeof(args)); | 3289 | memset(&args, 0, sizeof(args)); |
3245 | args.tp = tp; | 3290 | args.tp = tp; |
3246 | args.mp = ip->i_mount; | 3291 | args.mp = ip->i_mount; |
3247 | args.firstblock = *firstblock; | 3292 | args.firstblock = *firstblock; |
3248 | ASSERT((ifp->if_flags & | ||
3249 | (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); | ||
3250 | /* | 3293 | /* |
3251 | * Allocate a block. We know we need only one, since the | 3294 | * Allocate a block. We know we need only one, since the |
3252 | * file currently fits in an inode. | 3295 | * file currently fits in an inode. |
@@ -3259,20 +3302,21 @@ xfs_bmap_local_to_extents( | |||
3259 | args.type = XFS_ALLOCTYPE_NEAR_BNO; | 3302 | args.type = XFS_ALLOCTYPE_NEAR_BNO; |
3260 | } | 3303 | } |
3261 | args.total = total; | 3304 | args.total = total; |
3262 | args.mod = args.minleft = args.alignment = args.wasdel = | ||
3263 | args.isfl = args.minalignslop = 0; | ||
3264 | args.minlen = args.maxlen = args.prod = 1; | 3305 | args.minlen = args.maxlen = args.prod = 1; |
3265 | if ((error = xfs_alloc_vextent(&args))) | 3306 | error = xfs_alloc_vextent(&args); |
3307 | if (error) | ||
3266 | goto done; | 3308 | goto done; |
3267 | /* | 3309 | |
3268 | * Can't fail, the space was reserved. | 3310 | /* Can't fail, the space was reserved. */ |
3269 | */ | ||
3270 | ASSERT(args.fsbno != NULLFSBLOCK); | 3311 | ASSERT(args.fsbno != NULLFSBLOCK); |
3271 | ASSERT(args.len == 1); | 3312 | ASSERT(args.len == 1); |
3272 | *firstblock = args.fsbno; | 3313 | *firstblock = args.fsbno; |
3273 | bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); | 3314 | bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); |
3274 | bp->b_ops = &xfs_bmbt_buf_ops; | 3315 | |
3275 | memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); | 3316 | /* initialise the block and copy the data */ |
3317 | init_fn(bp, ip, ifp); | ||
3318 | |||
3319 | /* account for the change in fork size and log everything */ | ||
3276 | xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); | 3320 | xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); |
3277 | xfs_bmap_forkoff_reset(args.mp, ip, whichfork); | 3321 | xfs_bmap_forkoff_reset(args.mp, ip, whichfork); |
3278 | xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); | 3322 | xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); |
@@ -4680,9 +4724,6 @@ __xfs_bmapi_allocate( | |||
4680 | return error; | 4724 | return error; |
4681 | } | 4725 | } |
4682 | 4726 | ||
4683 | if (bma->flags & XFS_BMAPI_STACK_SWITCH) | ||
4684 | bma->stack_switch = 1; | ||
4685 | |||
4686 | error = xfs_bmap_alloc(bma); | 4727 | error = xfs_bmap_alloc(bma); |
4687 | if (error) | 4728 | if (error) |
4688 | return error; | 4729 | return error; |
@@ -4922,8 +4963,32 @@ xfs_bmapi_write( | |||
4922 | XFS_STATS_INC(xs_blk_mapw); | 4963 | XFS_STATS_INC(xs_blk_mapw); |
4923 | 4964 | ||
4924 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { | 4965 | if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { |
4966 | /* | ||
4967 | * XXX (dgc): This assumes we are only called for inodes that | ||
4968 | * contain content neutral data in local format. Anything that | ||
4969 | * contains caller-specific data in local format that needs | ||
4970 | * transformation to move to a block format needs to do the | ||
4971 | * conversion to extent format itself. | ||
4972 | * | ||
4973 | * Directory data forks and attribute forks handle this | ||
4974 | * themselves, but with the addition of metadata verifiers every | ||
4975 | * data fork in local format now contains caller specific data | ||
4976 | * and as such conversion through this function is likely to be | ||
4977 | * broken. | ||
4978 | * | ||
4979 | * The only likely user of this branch is for remote symlinks, | ||
4980 | * but we cannot overwrite the data fork contents of the symlink | ||
4981 | * (EEXIST occurs higher up the stack) and so it will never go | ||
4982 | * from local format to extent format here. Hence I don't think | ||
4983 | * this branch is ever executed intentionally and we should | ||
4984 | * consider removing it and asserting that xfs_bmapi_write() | ||
4985 | * cannot be called directly on local format forks. i.e. callers | ||
4986 | * are completely responsible for local to extent format | ||
4987 | * conversion, not xfs_bmapi_write(). | ||
4988 | */ | ||
4925 | error = xfs_bmap_local_to_extents(tp, ip, firstblock, total, | 4989 | error = xfs_bmap_local_to_extents(tp, ip, firstblock, total, |
4926 | &bma.logflags, whichfork); | 4990 | &bma.logflags, whichfork, |
4991 | xfs_bmap_local_to_extents_init_fn); | ||
4927 | if (error) | 4992 | if (error) |
4928 | goto error0; | 4993 | goto error0; |
4929 | } | 4994 | } |
@@ -4956,6 +5021,9 @@ xfs_bmapi_write( | |||
4956 | bma.flist = flist; | 5021 | bma.flist = flist; |
4957 | bma.firstblock = firstblock; | 5022 | bma.firstblock = firstblock; |
4958 | 5023 | ||
5024 | if (flags & XFS_BMAPI_STACK_SWITCH) | ||
5025 | bma.stack_switch = 1; | ||
5026 | |||
4959 | while (bno < end && n < *nmap) { | 5027 | while (bno < end && n < *nmap) { |
4960 | inhole = eof || bma.got.br_startoff > bno; | 5028 | inhole = eof || bma.got.br_startoff > bno; |
4961 | wasdelay = !inhole && isnullstartblock(bma.got.br_startblock); | 5029 | wasdelay = !inhole && isnullstartblock(bma.got.br_startblock); |