aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r--fs/xfs/xfs_bmap.c124
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 */
367STATIC void
368xfs_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
377STATIC void
378xfs_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 */
362STATIC int /* error */ 400STATIC int /* error */
363xfs_bmap_add_attrfork_local( 401xfs_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);