Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 352944
b: refs/heads/master
c: 1e82379
h: refs/heads/master
v: v3
  • Loading branch information
Dave Chinner authored and Ben Myers committed Feb 14, 2013
1 parent 37e62bc commit 9ca21f0
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fa5566e4ffb918131a054413eb42075a77a41413
refs/heads/master: 1e82379b018ceed0f0912327c60d73107dacbcb3
114 changes: 93 additions & 21 deletions trunk/fs/xfs/xfs_bmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,10 @@ xfs_bmap_local_to_extents(
xfs_fsblock_t *firstblock, /* first block allocated in xaction */
xfs_extlen_t total, /* total blocks needed by transaction */
int *logflagsp, /* inode logging flags */
int whichfork); /* data or attr fork */
int whichfork, /* data or attr fork */
void (*init_fn)(struct xfs_buf *bp,
struct xfs_inode *ip,
struct xfs_ifork *ifp));

/*
* Search the extents list for the inode, for the extent containing bno.
Expand Down Expand Up @@ -357,7 +360,42 @@ xfs_bmap_add_attrfork_extents(
}

/*
* Called from xfs_bmap_add_attrfork to handle local format files.
* Block initialisation functions for local to extent format conversion.
* As these get more complex, they will be moved to the relevant files,
* but for now they are too simple to worry about.
*/
STATIC void
xfs_bmap_local_to_extents_init_fn(
struct xfs_buf *bp,
struct xfs_inode *ip,
struct xfs_ifork *ifp)
{
bp->b_ops = &xfs_bmbt_buf_ops;
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
}

STATIC void
xfs_symlink_local_to_remote(
struct xfs_buf *bp,
struct xfs_inode *ip,
struct xfs_ifork *ifp)
{
/* remote symlink blocks are not verifiable until CRCs come along */
bp->b_ops = NULL;
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
}

/*
* Called from xfs_bmap_add_attrfork to handle local format files. Each
* different data fork content type needs a different callout to do the
* conversion. Some are basic and only require special block initialisation
* callouts for the data formating, others (directories) are so specialised they
* handle everything themselves.
*
* XXX (dgc): investigate whether directory conversion can use the generic
* formatting callout. It should be possible - it's just a very complex
* formatter. it would also require passing the transaction through to the init
* function.
*/
STATIC int /* error */
xfs_bmap_add_attrfork_local(
Expand All @@ -368,25 +406,29 @@ xfs_bmap_add_attrfork_local(
int *flags) /* inode logging flags */
{
xfs_da_args_t dargs; /* args for dir/attr code */
int error; /* error return value */
xfs_mount_t *mp; /* mount structure pointer */

if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip))
return 0;

if (S_ISDIR(ip->i_d.di_mode)) {
mp = ip->i_mount;
memset(&dargs, 0, sizeof(dargs));
dargs.dp = ip;
dargs.firstblock = firstblock;
dargs.flist = flist;
dargs.total = mp->m_dirblkfsbs;
dargs.total = ip->i_mount->m_dirblkfsbs;
dargs.whichfork = XFS_DATA_FORK;
dargs.trans = tp;
error = xfs_dir2_sf_to_block(&dargs);
} else
error = xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,
XFS_DATA_FORK);
return error;
return xfs_dir2_sf_to_block(&dargs);
}

if (S_ISLNK(ip->i_d.di_mode))
return xfs_bmap_local_to_extents(tp, ip, firstblock, 1,
flags, XFS_DATA_FORK,
xfs_symlink_local_to_remote);

return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags,
XFS_DATA_FORK,
xfs_bmap_local_to_extents_init_fn);
}

/*
Expand Down Expand Up @@ -3219,7 +3261,10 @@ xfs_bmap_local_to_extents(
xfs_fsblock_t *firstblock, /* first block allocated in xaction */
xfs_extlen_t total, /* total blocks needed by transaction */
int *logflagsp, /* inode logging flags */
int whichfork) /* data or attr fork */
int whichfork,
void (*init_fn)(struct xfs_buf *bp,
struct xfs_inode *ip,
struct xfs_ifork *ifp))
{
int error; /* error return value */
int flags; /* logging flags returned */
Expand All @@ -3239,12 +3284,12 @@ xfs_bmap_local_to_extents(
xfs_buf_t *bp; /* buffer for extent block */
xfs_bmbt_rec_host_t *ep;/* extent record pointer */

ASSERT((ifp->if_flags &
(XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE);
memset(&args, 0, sizeof(args));
args.tp = tp;
args.mp = ip->i_mount;
args.firstblock = *firstblock;
ASSERT((ifp->if_flags &
(XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE);
/*
* Allocate a block. We know we need only one, since the
* file currently fits in an inode.
Expand All @@ -3258,17 +3303,20 @@ xfs_bmap_local_to_extents(
}
args.total = total;
args.minlen = args.maxlen = args.prod = 1;
if ((error = xfs_alloc_vextent(&args)))
error = xfs_alloc_vextent(&args);
if (error)
goto done;
/*
* Can't fail, the space was reserved.
*/

/* Can't fail, the space was reserved. */
ASSERT(args.fsbno != NULLFSBLOCK);
ASSERT(args.len == 1);
*firstblock = args.fsbno;
bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
bp->b_ops = &xfs_bmbt_buf_ops;
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);

/* initialise the block and copy the data */
init_fn(bp, ip, ifp);

/* account for the change in fork size and log everything */
xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
Expand Down Expand Up @@ -4915,8 +4963,32 @@ xfs_bmapi_write(
XFS_STATS_INC(xs_blk_mapw);

if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
/*
* XXX (dgc): This assumes we are only called for inodes that
* contain content neutral data in local format. Anything that
* contains caller-specific data in local format that needs
* transformation to move to a block format needs to do the
* conversion to extent format itself.
*
* Directory data forks and attribute forks handle this
* themselves, but with the addition of metadata verifiers every
* data fork in local format now contains caller specific data
* and as such conversion through this function is likely to be
* broken.
*
* The only likely user of this branch is for remote symlinks,
* but we cannot overwrite the data fork contents of the symlink
* (EEXIST occurs higher up the stack) and so it will never go
* from local format to extent format here. Hence I don't think
* this branch is ever executed intentionally and we should
* consider removing it and asserting that xfs_bmapi_write()
* cannot be called directly on local format forks. i.e. callers
* are completely responsible for local to extent format
* conversion, not xfs_bmapi_write().
*/
error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
&bma.logflags, whichfork);
&bma.logflags, whichfork,
xfs_bmap_local_to_extents_init_fn);
if (error)
goto error0;
}
Expand Down

0 comments on commit 9ca21f0

Please sign in to comment.