xfs: update for 3.16-rc1

This update contains:
 o cleanup removing unused function args
 o rework of the filestreams allocator to use dentry cache parent lookups
 o new on-disk free inode btree and optimised inode allocator
 o various bug fixes
 o rework of internal attribute API
 o cleanup of superblock feature bit support to remove historic cruft
 o more fixes and minor cleanups
 o added a new directory/attribute geometry abstraction
 o yet more fixes and minor cleanups.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJTl+YfAAoJEK3oKUf0dfod/T8QALmvR28JZTL3vtlD5rppXp9+
 DXOMrwgJ9V+GOI39tpUgw1u/C5DuaFPRPtmCjnb9Do4DJMrHj+zD8ADvoVd6asa0
 FHH4TuulQqOJVu67SZ3ng15yjyy+wPfymQZIQPQY/IwVMUUEpWnSFnKha1GAsL8Y
 RY/WNU50wMu4wxi0++ENooHJC2EoxXpzB80cHddN81zFEFZobw0cm5Aa5xBZEZ4i
 P+GpEuUpWHKvVaWRLuIMgVC0NuOt5KtLfS97ong+tRgWCw//QVl28Rxhrj1ZHsF3
 VAskVsSFVIIPHP7qKjQyCGk71iqBfrfAgRqqJHFZgSmtSzyK3hVvJlRRDdCT5hi6
 00aHg9vz9815I7zrQwyMuy872N3DTislOxJZGD7PKgLpgfeHs4qk+cQ1xCi2gdFn
 xnh2p4mLolZHzanUsoxYpSh7f7o+NT3xgET3yS63uuO/I57o74JJDfRDjWNX6I9F
 LLtIGb1cwVFUYbXcHGfP1wxQ1BS6rYYYwKpSJqqwJXApL9MqoxH2B8Hoo0BaG43/
 3UlNi+yljvhBNiJnx2pAIdU+WaIL1ZQj9XzuU1sFSa8lnFNb2x+wkgjHzJ0Hdotm
 zZqirCo1jyyNkyTwGfwJwGzNgZemQDMQ7cr2MYzG1mhFMLEZZJeFmWVzfuzJ3yoR
 jke/Hy/qiWVK0en43MdR
 =qnz2
 -----END PGP SIGNATURE-----

Merge tag 'xfs-for-linus-3.16-rc1' of git://oss.sgi.com/xfs/xfs

Pull xfs updates from Dave Chinner:
 "This update contains:
   - cleanup removing unused function args
   - rework of the filestreams allocator to use dentry cache parent
     lookups
   - new on-disk free inode btree and optimised inode allocator
   - various bug fixes
   - rework of internal attribute API
   - cleanup of superblock feature bit support to remove historic cruft
   - more fixes and minor cleanups
   - added a new directory/attribute geometry abstraction
   - yet more fixes and minor cleanups"

* tag 'xfs-for-linus-3.16-rc1' of git://oss.sgi.com/xfs/xfs: (86 commits)
  xfs: fix xfs_da_args sparse warning in xfs_readdir
  xfs: Fix rounding in xfs_alloc_fix_len()
  xfs: tone down writepage/releasepage WARN_ONs
  xfs: small cleanup in xfs_lowbit64()
  xfs: kill xfs_buf_geterror()
  xfs: xfs_readsb needs to check for magic numbers
  xfs: block allocation work needs to be kswapd aware
  xfs: remove redundant geometry information from xfs_da_state
  xfs: replace attr LBSIZE with xfs_da_geometry
  xfs: pass xfs_da_args to xfs_attr_leaf_newentsize
  xfs: use xfs_da_geometry for block size in attr code
  xfs: remove mp->m_dir_geo from directory logging
  xfs: reduce direct usage of mp->m_dir_geo
  xfs: move node entry counts to xfs_da_geometry
  xfs: convert dir/attr btree threshold to xfs_da_geometry
  xfs: convert m_dirblksize to xfs_da_geometry
  xfs: convert m_dirblkfsbs to xfs_da_geometry
  xfs: convert directory segment limits to xfs_da_geometry
  xfs: convert directory db conversion to xfs_da_geometry
  xfs: convert directory dablk conversion to xfs_da_geometry
  ...
This commit is contained in:
Linus Torvalds 2014-06-11 09:03:47 -07:00
commit 412dd3a6da
92 changed files with 2662 additions and 2799 deletions

View file

@ -278,6 +278,17 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
return ret;
}
static int quota_rmxquota(struct super_block *sb, void __user *addr)
{
__u32 flags;
if (copy_from_user(&flags, addr, sizeof(flags)))
return -EFAULT;
if (!sb->s_qcop->rm_xquota)
return -ENOSYS;
return sb->s_qcop->rm_xquota(sb, flags);
}
/* Copy parameters and call proper function */
static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
void __user *addr, struct path *path)
@ -316,8 +327,9 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
return sb->s_qcop->quota_sync(sb, type);
case Q_XQUOTAON:
case Q_XQUOTAOFF:
case Q_XQUOTARM:
return quota_setxstate(sb, cmd, addr);
case Q_XQUOTARM:
return quota_rmxquota(sb, addr);
case Q_XGETQSTAT:
return quota_getxstate(sb, addr);
case Q_XGETQSTATV:

View file

@ -160,30 +160,38 @@ typedef struct xfs_agi {
* still being referenced.
*/
__be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS];
/*
* This marks the end of logging region 1 and start of logging region 2.
*/
uuid_t agi_uuid; /* uuid of filesystem */
__be32 agi_crc; /* crc of agi sector */
__be32 agi_pad32;
__be64 agi_lsn; /* last write sequence */
__be32 agi_free_root; /* root of the free inode btree */
__be32 agi_free_level;/* levels in free inode btree */
/* structure must be padded to 64 bit alignment */
} xfs_agi_t;
#define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc)
#define XFS_AGI_MAGICNUM 0x00000001
#define XFS_AGI_VERSIONNUM 0x00000002
#define XFS_AGI_SEQNO 0x00000004
#define XFS_AGI_LENGTH 0x00000008
#define XFS_AGI_COUNT 0x00000010
#define XFS_AGI_ROOT 0x00000020
#define XFS_AGI_LEVEL 0x00000040
#define XFS_AGI_FREECOUNT 0x00000080
#define XFS_AGI_NEWINO 0x00000100
#define XFS_AGI_DIRINO 0x00000200
#define XFS_AGI_UNLINKED 0x00000400
#define XFS_AGI_NUM_BITS 11
#define XFS_AGI_ALL_BITS ((1 << XFS_AGI_NUM_BITS) - 1)
#define XFS_AGI_MAGICNUM (1 << 0)
#define XFS_AGI_VERSIONNUM (1 << 1)
#define XFS_AGI_SEQNO (1 << 2)
#define XFS_AGI_LENGTH (1 << 3)
#define XFS_AGI_COUNT (1 << 4)
#define XFS_AGI_ROOT (1 << 5)
#define XFS_AGI_LEVEL (1 << 6)
#define XFS_AGI_FREECOUNT (1 << 7)
#define XFS_AGI_NEWINO (1 << 8)
#define XFS_AGI_DIRINO (1 << 9)
#define XFS_AGI_UNLINKED (1 << 10)
#define XFS_AGI_NUM_BITS_R1 11 /* end of the 1st agi logging region */
#define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1)
#define XFS_AGI_FREE_ROOT (1 << 11)
#define XFS_AGI_FREE_LEVEL (1 << 12)
#define XFS_AGI_NUM_BITS_R2 13
/* disk block (xfs_daddr_t) in the AG */
#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log))

View file

@ -257,16 +257,14 @@ xfs_alloc_fix_len(
k = rlen % args->prod;
if (k == args->mod)
return;
if (k > args->mod) {
if ((int)(rlen = rlen - k - args->mod) < (int)args->minlen)
return;
} else {
if ((int)(rlen = rlen - args->prod - (args->mod - k)) <
(int)args->minlen)
return;
}
ASSERT(rlen >= args->minlen);
ASSERT(rlen <= args->maxlen);
if (k > args->mod)
rlen = rlen - (k - args->mod);
else
rlen = rlen - args->prod + (args->mod - k);
if ((int)rlen < (int)args->minlen)
return;
ASSERT(rlen >= args->minlen && rlen <= args->maxlen);
ASSERT(rlen % args->prod == args->mod);
args->len = rlen;
}
@ -541,7 +539,6 @@ xfs_alloc_read_agfl(
XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops);
if (error)
return error;
ASSERT(!xfs_buf_geterror(bp));
xfs_buf_set_ref(bp, XFS_AGFL_REF);
*bpp = bp;
return 0;

View file

@ -70,7 +70,6 @@ xfs_allocbt_alloc_block(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *start,
union xfs_btree_ptr *new,
int length,
int *stat)
{
int error;

View file

@ -975,14 +975,39 @@ xfs_vm_writepage(
* Given that we do not allow direct reclaim to call us, we should
* never be called while in a filesystem transaction.
*/
if (WARN_ON(current->flags & PF_FSTRANS))
if (WARN_ON_ONCE(current->flags & PF_FSTRANS))
goto redirty;
/* Is this page beyond the end of the file? */
offset = i_size_read(inode);
end_index = offset >> PAGE_CACHE_SHIFT;
last_index = (offset - 1) >> PAGE_CACHE_SHIFT;
if (page->index >= end_index) {
/*
* The page index is less than the end_index, adjust the end_offset
* to the highest offset that this page should represent.
* -----------------------------------------------------
* | file mapping | <EOF> |
* -----------------------------------------------------
* | Page ... | Page N-2 | Page N-1 | Page N | |
* ^--------------------------------^----------|--------
* | desired writeback range | see else |
* ---------------------------------^------------------|
*/
if (page->index < end_index)
end_offset = (xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT;
else {
/*
* Check whether the page to write out is beyond or straddles
* i_size or not.
* -------------------------------------------------------
* | file mapping | <EOF> |
* -------------------------------------------------------
* | Page ... | Page N-2 | Page N-1 | Page N | Beyond |
* ^--------------------------------^-----------|---------
* | | Straddles |
* ---------------------------------^-----------|--------|
*/
unsigned offset_into_page = offset & (PAGE_CACHE_SIZE - 1);
/*
@ -990,24 +1015,36 @@ xfs_vm_writepage(
* truncate operation that is in progress. We must redirty the
* page so that reclaim stops reclaiming it. Otherwise
* xfs_vm_releasepage() is called on it and gets confused.
*
* Note that the end_index is unsigned long, it would overflow
* if the given offset is greater than 16TB on 32-bit system
* and if we do check the page is fully outside i_size or not
* via "if (page->index >= end_index + 1)" as "end_index + 1"
* will be evaluated to 0. Hence this page will be redirtied
* and be written out repeatedly which would result in an
* infinite loop, the user program that perform this operation
* will hang. Instead, we can verify this situation by checking
* if the page to write is totally beyond the i_size or if it's
* offset is just equal to the EOF.
*/
if (page->index >= end_index + 1 || offset_into_page == 0)
if (page->index > end_index ||
(page->index == end_index && offset_into_page == 0))
goto redirty;
/*
* The page straddles i_size. It must be zeroed out on each
* and every writepage invocation because it may be mmapped.
* "A file is mapped in multiples of the page size. For a file
* that is not a multiple of the page size, the remaining
* that is not a multiple of the page size, the remaining
* memory is zeroed when mapped, and writes to that region are
* not written out to the file."
*/
zero_user_segment(page, offset_into_page, PAGE_CACHE_SIZE);
/* Adjust the end_offset to the end of file */
end_offset = offset;
}
end_offset = min_t(unsigned long long,
(xfs_off_t)(page->index + 1) << PAGE_CACHE_SHIFT,
offset);
len = 1 << inode->i_blkbits;
bh = head = page_buffers(page);
@ -1188,9 +1225,9 @@ xfs_vm_releasepage(
xfs_count_page_state(page, &delalloc, &unwritten);
if (WARN_ON(delalloc))
if (WARN_ON_ONCE(delalloc))
return 0;
if (WARN_ON(unwritten))
if (WARN_ON_ONCE(unwritten))
return 0;
return try_to_free_buffers(page);

View file

@ -77,17 +77,27 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
STATIC int
xfs_attr_name_to_xname(
struct xfs_name *xname,
const unsigned char *aname)
xfs_attr_args_init(
struct xfs_da_args *args,
struct xfs_inode *dp,
const unsigned char *name,
int flags)
{
if (!aname)
if (!name)
return EINVAL;
xname->name = aname;
xname->len = strlen((char *)aname);
if (xname->len >= MAXNAMELEN)
memset(args, 0, sizeof(*args));
args->geo = dp->i_mount->m_attr_geo;
args->whichfork = XFS_ATTR_FORK;
args->dp = dp;
args->flags = flags;
args->name = name;
args->namelen = strlen((const char *)name);
if (args->namelen >= MAXNAMELEN)
return EFAULT; /* match IRIX behaviour */
args->hashval = xfs_da_hashname(args->name, args->namelen);
return 0;
}
@ -106,79 +116,46 @@ xfs_inode_hasattr(
* Overall external interface routines.
*========================================================================*/
STATIC int
xfs_attr_get_int(
int
xfs_attr_get(
struct xfs_inode *ip,
struct xfs_name *name,
const unsigned char *name,
unsigned char *value,
int *valuelenp,
int flags)
{
xfs_da_args_t args;
int error;
if (!xfs_inode_hasattr(ip))
return ENOATTR;
/*
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
args.name = name->name;
args.namelen = name->len;
args.value = value;
args.valuelen = *valuelenp;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = ip;
args.whichfork = XFS_ATTR_FORK;
/*
* Decide on what work routines to call based on the inode size.
*/
if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
error = xfs_attr_shortform_getvalue(&args);
} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
error = xfs_attr_leaf_get(&args);
} else {
error = xfs_attr_node_get(&args);
}
/*
* Return the number of bytes in the value to the caller.
*/
*valuelenp = args.valuelen;
if (error == EEXIST)
error = 0;
return(error);
}
int
xfs_attr_get(
xfs_inode_t *ip,
const unsigned char *name,
unsigned char *value,
int *valuelenp,
int flags)
{
int error;
struct xfs_name xname;
uint lock_mode;
struct xfs_da_args args;
uint lock_mode;
int error;
XFS_STATS_INC(xs_attr_get);
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return(EIO);
return EIO;
error = xfs_attr_name_to_xname(&xname, name);
if (!xfs_inode_hasattr(ip))
return ENOATTR;
error = xfs_attr_args_init(&args, ip, name, flags);
if (error)
return error;
args.value = value;
args.valuelen = *valuelenp;
lock_mode = xfs_ilock_attr_map_shared(ip);
error = xfs_attr_get_int(ip, &xname, value, valuelenp, flags);
if (!xfs_inode_hasattr(ip))
error = ENOATTR;
else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
error = xfs_attr_shortform_getvalue(&args);
else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
error = xfs_attr_leaf_get(&args);
else
error = xfs_attr_node_get(&args);
xfs_iunlock(ip, lock_mode);
return(error);
*valuelenp = args.valuelen;
return error == EEXIST ? 0 : error;
}
/*
@ -186,12 +163,10 @@ xfs_attr_get(
*/
STATIC int
xfs_attr_calc_size(
struct xfs_inode *ip,
int namelen,
int valuelen,
struct xfs_da_args *args,
int *local)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_mount *mp = args->dp->i_mount;
int size;
int nblks;
@ -199,12 +174,10 @@ xfs_attr_calc_size(
* Determine space new attribute will use, and if it would be
* "local" or "remote" (note: local != inline).
*/
size = xfs_attr_leaf_newentsize(namelen, valuelen,
mp->m_sb.sb_blocksize, local);
size = xfs_attr_leaf_newentsize(args, local);
nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
if (*local) {
if (size > (mp->m_sb.sb_blocksize >> 1)) {
if (size > (args->geo->blksize / 2)) {
/* Double split possible */
nblks *= 2;
}
@ -213,7 +186,7 @@ xfs_attr_calc_size(
* Out of line attribute, cannot double split, but
* make room for the attribute value itself.
*/
uint dblocks = xfs_attr3_rmt_blocks(mp, valuelen);
uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
nblks += dblocks;
nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
}
@ -221,26 +194,38 @@ xfs_attr_calc_size(
return nblks;
}
STATIC int
xfs_attr_set_int(
struct xfs_inode *dp,
struct xfs_name *name,
unsigned char *value,
int valuelen,
int flags)
int
xfs_attr_set(
struct xfs_inode *dp,
const unsigned char *name,
unsigned char *value,
int valuelen,
int flags)
{
xfs_da_args_t args;
xfs_fsblock_t firstblock;
xfs_bmap_free_t flist;
int error, err2, committed;
struct xfs_mount *mp = dp->i_mount;
struct xfs_da_args args;
struct xfs_bmap_free flist;
struct xfs_trans_res tres;
xfs_fsblock_t firstblock;
int rsvd = (flags & ATTR_ROOT) != 0;
int local;
int error, err2, committed, local;
XFS_STATS_INC(xs_attr_set);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return EIO;
error = xfs_attr_args_init(&args, dp, name, flags);
if (error)
return error;
args.value = value;
args.valuelen = valuelen;
args.firstblock = &firstblock;
args.flist = &flist;
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
args.total = xfs_attr_calc_size(&args, &local);
/*
* Attach the dquots to the inode.
*/
error = xfs_qm_dqattach(dp, 0);
if (error)
return error;
@ -251,31 +236,13 @@ xfs_attr_set_int(
*/
if (XFS_IFORK_Q(dp) == 0) {
int sf_size = sizeof(xfs_attr_sf_hdr_t) +
XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd)))
return(error);
error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
if (error)
return error;
}
/*
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
args.name = name->name;
args.namelen = name->len;
args.value = value;
args.valuelen = valuelen;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = dp;
args.firstblock = &firstblock;
args.flist = &flist;
args.whichfork = XFS_ATTR_FORK;
args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
/* Size is now blocks for attribute data */
args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local);
/*
* Start our first transaction of the day.
*
@ -303,7 +270,7 @@ xfs_attr_set_int(
error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
if (error) {
xfs_trans_cancel(args.trans, 0);
return(error);
return error;
}
xfs_ilock(dp, XFS_ILOCK_EXCL);
@ -313,7 +280,7 @@ xfs_attr_set_int(
if (error) {
xfs_iunlock(dp, XFS_ILOCK_EXCL);
xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
return (error);
return error;
}
xfs_trans_ijoin(args.trans, dp, 0);
@ -322,9 +289,9 @@ xfs_attr_set_int(
* If the attribute list is non-existent or a shortform list,
* upgrade it to a single-leaf-block attribute list.
*/
if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
(dp->i_d.di_anextents == 0))) {
if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
dp->i_d.di_anextents == 0)) {
/*
* Build initial attribute list (if required).
@ -349,9 +316,8 @@ xfs_attr_set_int(
* the transaction goes to disk before returning
* to the user.
*/
if (mp->m_flags & XFS_MOUNT_WSYNC) {
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans);
}
if (!error && (flags & ATTR_KERNOTIME) == 0) {
xfs_trans_ichgtime(args.trans, dp,
@ -361,7 +327,7 @@ xfs_attr_set_int(
XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error == 0 ? err2 : error);
return error ? error : err2;
}
/*
@ -399,22 +365,19 @@ xfs_attr_set_int(
}
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
error = xfs_attr_leaf_addname(&args);
} else {
else
error = xfs_attr_node_addname(&args);
}
if (error) {
if (error)
goto out;
}
/*
* If this is a synchronous mount, make sure that the
* transaction goes to disk before returning to the user.
*/
if (mp->m_flags & XFS_MOUNT_WSYNC) {
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans);
}
if ((flags & ATTR_KERNOTIME) == 0)
xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@ -426,65 +389,47 @@ xfs_attr_set_int(
error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error);
return error;
out:
if (args.trans)
if (args.trans) {
xfs_trans_cancel(args.trans,
XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
}
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error);
}
int
xfs_attr_set(
xfs_inode_t *dp,
const unsigned char *name,
unsigned char *value,
int valuelen,
int flags)
{
int error;
struct xfs_name xname;
XFS_STATS_INC(xs_attr_set);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO);
error = xfs_attr_name_to_xname(&xname, name);
if (error)
return error;
return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
return error;
}
/*
* Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary.
*/
STATIC int
xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
int
xfs_attr_remove(
struct xfs_inode *dp,
const unsigned char *name,
int flags)
{
xfs_da_args_t args;
xfs_fsblock_t firstblock;
xfs_bmap_free_t flist;
int error;
xfs_mount_t *mp = dp->i_mount;
struct xfs_mount *mp = dp->i_mount;
struct xfs_da_args args;
struct xfs_bmap_free flist;
xfs_fsblock_t firstblock;
int error;
XFS_STATS_INC(xs_attr_remove);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return EIO;
if (!xfs_inode_hasattr(dp))
return ENOATTR;
error = xfs_attr_args_init(&args, dp, name, flags);
if (error)
return error;
/*
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
args.name = name->name;
args.namelen = name->len;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = dp;
args.firstblock = &firstblock;
args.flist = &flist;
args.total = 0;
args.whichfork = XFS_ATTR_FORK;
/*
* we have no control over the attribute names that userspace passes us
@ -493,9 +438,6 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
*/
args.op_flags = XFS_DA_OP_OKNOENT;
/*
* Attach the dquots to the inode.
*/
error = xfs_qm_dqattach(dp, 0);
if (error)
return error;
@ -524,7 +466,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
XFS_ATTRRM_SPACE_RES(mp), 0);
if (error) {
xfs_trans_cancel(args.trans, 0);
return(error);
return error;
}
xfs_ilock(dp, XFS_ILOCK_EXCL);
@ -534,35 +476,26 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
*/
xfs_trans_ijoin(args.trans, dp, 0);
/*
* Decide on what work routines to call based on the inode size.
*/
if (!xfs_inode_hasattr(dp)) {
error = XFS_ERROR(ENOATTR);
goto out;
}
if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
error = xfs_attr_shortform_remove(&args);
if (error) {
goto out;
}
} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
error = xfs_attr_leaf_removename(&args);
} else {
error = xfs_attr_node_removename(&args);
}
if (error) {
if (error)
goto out;
}
/*
* If this is a synchronous mount, make sure that the
* transaction goes to disk before returning to the user.
*/
if (mp->m_flags & XFS_MOUNT_WSYNC) {
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(args.trans);
}
if ((flags & ATTR_KERNOTIME) == 0)
xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@ -574,45 +507,17 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error);
return error;
out:
if (args.trans)
if (args.trans) {
xfs_trans_cancel(args.trans,
XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error);
}
int
xfs_attr_remove(
xfs_inode_t *dp,
const unsigned char *name,
int flags)
{
int error;
struct xfs_name xname;
XFS_STATS_INC(xs_attr_remove);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO);
error = xfs_attr_name_to_xname(&xname, name);
if (error)
return error;
xfs_ilock(dp, XFS_ILOCK_SHARED);
if (!xfs_inode_hasattr(dp)) {
xfs_iunlock(dp, XFS_ILOCK_SHARED);
return XFS_ERROR(ENOATTR);
}
xfs_iunlock(dp, XFS_ILOCK_SHARED);
return xfs_attr_remove_int(dp, &xname, flags);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return error;
}
/*========================================================================
* External routines when attribute list is inside the inode
*========================================================================*/
@ -958,7 +863,7 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
}
/*========================================================================
* External routines when attribute list size > XFS_LBSIZE(mp).
* External routines when attribute list size > geo->blksize
*========================================================================*/
/*
@ -991,8 +896,6 @@ xfs_attr_node_addname(xfs_da_args_t *args)
state = xfs_da_state_alloc();
state->args = args;
state->mp = mp;
state->blocksize = state->mp->m_sb.sb_blocksize;
state->node_ents = state->mp->m_attr_node_ents;
/*
* Search to see if name already exists, and get back a pointer
@ -1170,8 +1073,6 @@ xfs_attr_node_addname(xfs_da_args_t *args)
state = xfs_da_state_alloc();
state->args = args;
state->mp = mp;
state->blocksize = state->mp->m_sb.sb_blocksize;
state->node_ents = state->mp->m_attr_node_ents;
state->inleaf = 0;
error = xfs_da3_node_lookup_int(state, &retval);
if (error)
@ -1262,8 +1163,6 @@ xfs_attr_node_removename(xfs_da_args_t *args)
state = xfs_da_state_alloc();
state->args = args;
state->mp = dp->i_mount;
state->blocksize = state->mp->m_sb.sb_blocksize;
state->node_ents = state->mp->m_attr_node_ents;
/*
* Search to see if name exists, and get back a pointer to it.
@ -1525,8 +1424,6 @@ xfs_attr_node_get(xfs_da_args_t *args)
state = xfs_da_state_alloc();
state->args = args;
state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_sb.sb_blocksize;
state->node_ents = state->mp->m_attr_node_ents;
/*
* Search to see if name exists, and get back a pointer to it.

View file

@ -80,11 +80,12 @@ STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state,
/*
* Utility routines.
*/
STATIC void xfs_attr3_leaf_moveents(struct xfs_attr_leafblock *src_leaf,
STATIC void xfs_attr3_leaf_moveents(struct xfs_da_args *args,
struct xfs_attr_leafblock *src_leaf,
struct xfs_attr3_icleaf_hdr *src_ichdr, int src_start,
struct xfs_attr_leafblock *dst_leaf,
struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start,
int move_count, struct xfs_mount *mp);
int move_count);
STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
void
@ -711,6 +712,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
memset((char *)&nargs, 0, sizeof(nargs));
nargs.dp = dp;
nargs.geo = args->geo;
nargs.firstblock = args->firstblock;
nargs.flist = args->flist;
nargs.total = args->total;
@ -805,18 +807,18 @@ xfs_attr3_leaf_to_shortform(
trace_xfs_attr_leaf_to_sf(args);
tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP);
if (!tmpbuffer)
return ENOMEM;
memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(dp->i_mount));
memcpy(tmpbuffer, bp->b_addr, args->geo->blksize);
leaf = (xfs_attr_leafblock_t *)tmpbuffer;
xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
entry = xfs_attr3_leaf_entryp(leaf);
/* XXX (dgc): buffer is about to be marked stale - why zero it? */
memset(bp->b_addr, 0, XFS_LBSIZE(dp->i_mount));
memset(bp->b_addr, 0, args->geo->blksize);
/*
* Clean out the prior contents of the attribute list.
@ -838,6 +840,7 @@ xfs_attr3_leaf_to_shortform(
* Copy the attributes
*/
memset((char *)&nargs, 0, sizeof(nargs));
nargs.geo = args->geo;
nargs.dp = dp;
nargs.firstblock = args->firstblock;
nargs.flist = args->flist;
@ -904,12 +907,12 @@ xfs_attr3_leaf_to_node(
/* copy leaf to new buffer, update identifiers */
xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF);
bp2->b_ops = bp1->b_ops;
memcpy(bp2->b_addr, bp1->b_addr, XFS_LBSIZE(mp));
memcpy(bp2->b_addr, bp1->b_addr, args->geo->blksize);
if (xfs_sb_version_hascrc(&mp->m_sb)) {
struct xfs_da3_blkinfo *hdr3 = bp2->b_addr;
hdr3->blkno = cpu_to_be64(bp2->b_bn);
}
xfs_trans_log_buf(args->trans, bp2, 0, XFS_LBSIZE(mp) - 1);
xfs_trans_log_buf(args->trans, bp2, 0, args->geo->blksize - 1);
/*
* Set up the new root node.
@ -930,7 +933,7 @@ xfs_attr3_leaf_to_node(
btree[0].before = cpu_to_be32(blkno);
icnodehdr.count = 1;
dp->d_ops->node_hdr_to_disk(node, &icnodehdr);
xfs_trans_log_buf(args->trans, bp1, 0, XFS_LBSIZE(mp) - 1);
xfs_trans_log_buf(args->trans, bp1, 0, args->geo->blksize - 1);
error = 0;
out:
return error;
@ -966,10 +969,10 @@ xfs_attr3_leaf_create(
bp->b_ops = &xfs_attr3_leaf_buf_ops;
xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF);
leaf = bp->b_addr;
memset(leaf, 0, XFS_LBSIZE(mp));
memset(leaf, 0, args->geo->blksize);
memset(&ichdr, 0, sizeof(ichdr));
ichdr.firstused = XFS_LBSIZE(mp);
ichdr.firstused = args->geo->blksize;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
struct xfs_da3_blkinfo *hdr3 = bp->b_addr;
@ -988,7 +991,7 @@ xfs_attr3_leaf_create(
ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base;
xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr);
xfs_trans_log_buf(args->trans, bp, 0, XFS_LBSIZE(mp) - 1);
xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1);
*bpp = bp;
return 0;
@ -1074,8 +1077,7 @@ xfs_attr3_leaf_add(
leaf = bp->b_addr;
xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
ASSERT(args->index >= 0 && args->index <= ichdr.count);
entsize = xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
args->trans->t_mountp->m_sb.sb_blocksize, NULL);
entsize = xfs_attr_leaf_newentsize(args, NULL);
/*
* Search through freemap for first-fit on new name length.
@ -1174,17 +1176,14 @@ xfs_attr3_leaf_add_work(
* Allocate space for the new string (at the end of the run).
*/
mp = args->trans->t_mountp;
ASSERT(ichdr->freemap[mapindex].base < XFS_LBSIZE(mp));
ASSERT(ichdr->freemap[mapindex].base < args->geo->blksize);
ASSERT((ichdr->freemap[mapindex].base & 0x3) == 0);
ASSERT(ichdr->freemap[mapindex].size >=
xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
mp->m_sb.sb_blocksize, NULL));
ASSERT(ichdr->freemap[mapindex].size < XFS_LBSIZE(mp));
xfs_attr_leaf_newentsize(args, NULL));
ASSERT(ichdr->freemap[mapindex].size < args->geo->blksize);
ASSERT((ichdr->freemap[mapindex].size & 0x3) == 0);
ichdr->freemap[mapindex].size -=
xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
mp->m_sb.sb_blocksize, &tmp);
ichdr->freemap[mapindex].size -= xfs_attr_leaf_newentsize(args, &tmp);
entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base +
ichdr->freemap[mapindex].size);
@ -1269,14 +1268,13 @@ xfs_attr3_leaf_compact(
struct xfs_attr_leafblock *leaf_dst;
struct xfs_attr3_icleaf_hdr ichdr_src;
struct xfs_trans *trans = args->trans;
struct xfs_mount *mp = trans->t_mountp;
char *tmpbuffer;
trace_xfs_attr_leaf_compact(args);
tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(mp));
memset(bp->b_addr, 0, XFS_LBSIZE(mp));
tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP);
memcpy(tmpbuffer, bp->b_addr, args->geo->blksize);
memset(bp->b_addr, 0, args->geo->blksize);
leaf_src = (xfs_attr_leafblock_t *)tmpbuffer;
leaf_dst = bp->b_addr;
@ -1289,7 +1287,7 @@ xfs_attr3_leaf_compact(
/* Initialise the incore headers */
ichdr_src = *ichdr_dst; /* struct copy */
ichdr_dst->firstused = XFS_LBSIZE(mp);
ichdr_dst->firstused = args->geo->blksize;
ichdr_dst->usedbytes = 0;
ichdr_dst->count = 0;
ichdr_dst->holes = 0;
@ -1304,13 +1302,13 @@ xfs_attr3_leaf_compact(
* Copy all entry's in the same (sorted) order,
* but allocate name/value pairs packed and in sequence.
*/
xfs_attr3_leaf_moveents(leaf_src, &ichdr_src, 0, leaf_dst, ichdr_dst, 0,
ichdr_src.count, mp);
xfs_attr3_leaf_moveents(args, leaf_src, &ichdr_src, 0,
leaf_dst, ichdr_dst, 0, ichdr_src.count);
/*
* this logs the entire buffer, but the caller must write the header
* back to the buffer when it is finished modifying it.
*/
xfs_trans_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
xfs_trans_log_buf(trans, bp, 0, args->geo->blksize - 1);
kmem_free(tmpbuffer);
}
@ -1461,8 +1459,8 @@ xfs_attr3_leaf_rebalance(
/*
* Move high entries from leaf1 to low end of leaf2.
*/
xfs_attr3_leaf_moveents(leaf1, &ichdr1, ichdr1.count - count,
leaf2, &ichdr2, 0, count, state->mp);
xfs_attr3_leaf_moveents(args, leaf1, &ichdr1,
ichdr1.count - count, leaf2, &ichdr2, 0, count);
} else if (count > ichdr1.count) {
/*
@ -1490,14 +1488,14 @@ xfs_attr3_leaf_rebalance(
/*
* Move low entries from leaf2 to high end of leaf1.
*/
xfs_attr3_leaf_moveents(leaf2, &ichdr2, 0, leaf1, &ichdr1,
ichdr1.count, count, state->mp);
xfs_attr3_leaf_moveents(args, leaf2, &ichdr2, 0, leaf1, &ichdr1,
ichdr1.count, count);
}
xfs_attr3_leaf_hdr_to_disk(leaf1, &ichdr1);
xfs_attr3_leaf_hdr_to_disk(leaf2, &ichdr2);
xfs_trans_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
xfs_trans_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
xfs_trans_log_buf(args->trans, blk1->bp, 0, args->geo->blksize - 1);
xfs_trans_log_buf(args->trans, blk2->bp, 0, args->geo->blksize - 1);
/*
* Copy out last hashval in each block for B-tree code.
@ -1592,11 +1590,9 @@ xfs_attr3_leaf_figure_balance(
max = ichdr1->count + ichdr2->count;
half = (max + 1) * sizeof(*entry);
half += ichdr1->usedbytes + ichdr2->usedbytes +
xfs_attr_leaf_newentsize(state->args->namelen,
state->args->valuelen,
state->blocksize, NULL);
xfs_attr_leaf_newentsize(state->args, NULL);
half /= 2;
lastdelta = state->blocksize;
lastdelta = state->args->geo->blksize;
entry = xfs_attr3_leaf_entryp(leaf1);
for (count = index = 0; count < max; entry++, index++, count++) {
@ -1606,10 +1602,7 @@ xfs_attr3_leaf_figure_balance(
*/
if (count == blk1->index) {
tmp = totallen + sizeof(*entry) +
xfs_attr_leaf_newentsize(
state->args->namelen,
state->args->valuelen,
state->blocksize, NULL);
xfs_attr_leaf_newentsize(state->args, NULL);
if (XFS_ATTR_ABS(half - tmp) > lastdelta)
break;
lastdelta = XFS_ATTR_ABS(half - tmp);
@ -1645,10 +1638,7 @@ xfs_attr3_leaf_figure_balance(
totallen -= count * sizeof(*entry);
if (foundit) {
totallen -= sizeof(*entry) +
xfs_attr_leaf_newentsize(
state->args->namelen,
state->args->valuelen,
state->blocksize, NULL);
xfs_attr_leaf_newentsize(state->args, NULL);
}
*countarg = count;
@ -1700,7 +1690,7 @@ xfs_attr3_leaf_toosmall(
bytes = xfs_attr3_leaf_hdr_size(leaf) +
ichdr.count * sizeof(xfs_attr_leaf_entry_t) +
ichdr.usedbytes;
if (bytes > (state->blocksize >> 1)) {
if (bytes > (state->args->geo->blksize >> 1)) {
*action = 0; /* blk over 50%, don't try to join */
return(0);
}
@ -1754,7 +1744,8 @@ xfs_attr3_leaf_toosmall(
xfs_attr3_leaf_hdr_from_disk(&ichdr2, bp->b_addr);
bytes = state->blocksize - (state->blocksize >> 2) -
bytes = state->args->geo->blksize -
(state->args->geo->blksize >> 2) -
ichdr.usedbytes - ichdr2.usedbytes -
((ichdr.count + ichdr2.count) *
sizeof(xfs_attr_leaf_entry_t)) -
@ -1805,7 +1796,6 @@ xfs_attr3_leaf_remove(
struct xfs_attr_leafblock *leaf;
struct xfs_attr3_icleaf_hdr ichdr;
struct xfs_attr_leaf_entry *entry;
struct xfs_mount *mp = args->trans->t_mountp;
int before;
int after;
int smallest;
@ -1819,7 +1809,7 @@ xfs_attr3_leaf_remove(
leaf = bp->b_addr;
xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
ASSERT(ichdr.count > 0 && ichdr.count < XFS_LBSIZE(mp) / 8);
ASSERT(ichdr.count > 0 && ichdr.count < args->geo->blksize / 8);
ASSERT(args->index >= 0 && args->index < ichdr.count);
ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) +
xfs_attr3_leaf_hdr_size(leaf));
@ -1827,7 +1817,7 @@ xfs_attr3_leaf_remove(
entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused);
ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize);
/*
* Scan through free region table:
@ -1842,8 +1832,8 @@ xfs_attr3_leaf_remove(
smallest = XFS_ATTR_LEAF_MAPSIZE - 1;
entsize = xfs_attr_leaf_entsize(leaf, args->index);
for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
ASSERT(ichdr.freemap[i].base < XFS_LBSIZE(mp));
ASSERT(ichdr.freemap[i].size < XFS_LBSIZE(mp));
ASSERT(ichdr.freemap[i].base < args->geo->blksize);
ASSERT(ichdr.freemap[i].size < args->geo->blksize);
if (ichdr.freemap[i].base == tablesize) {
ichdr.freemap[i].base -= sizeof(xfs_attr_leaf_entry_t);
ichdr.freemap[i].size += sizeof(xfs_attr_leaf_entry_t);
@ -1920,11 +1910,11 @@ xfs_attr3_leaf_remove(
* removing the name.
*/
if (smallest) {
tmp = XFS_LBSIZE(mp);
tmp = args->geo->blksize;
entry = xfs_attr3_leaf_entryp(leaf);
for (i = ichdr.count - 1; i >= 0; entry++, i--) {
ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused);
ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize);
if (be16_to_cpu(entry->nameidx) < tmp)
tmp = be16_to_cpu(entry->nameidx);
@ -1947,7 +1937,7 @@ xfs_attr3_leaf_remove(
tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) +
ichdr.count * sizeof(xfs_attr_leaf_entry_t);
return tmp < mp->m_attr_magicpct; /* leaf is < 37% full */
return tmp < args->geo->magicpct; /* leaf is < 37% full */
}
/*
@ -1964,7 +1954,6 @@ xfs_attr3_leaf_unbalance(
struct xfs_attr3_icleaf_hdr drophdr;
struct xfs_attr3_icleaf_hdr savehdr;
struct xfs_attr_leaf_entry *entry;
struct xfs_mount *mp = state->mp;
trace_xfs_attr_leaf_unbalance(state->args);
@ -1991,13 +1980,15 @@ xfs_attr3_leaf_unbalance(
*/
if (xfs_attr3_leaf_order(save_blk->bp, &savehdr,
drop_blk->bp, &drophdr)) {
xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
xfs_attr3_leaf_moveents(state->args,
drop_leaf, &drophdr, 0,
save_leaf, &savehdr, 0,
drophdr.count, mp);
drophdr.count);
} else {
xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
xfs_attr3_leaf_moveents(state->args,
drop_leaf, &drophdr, 0,
save_leaf, &savehdr,
savehdr.count, drophdr.count, mp);
savehdr.count, drophdr.count);
}
} else {
/*
@ -2007,7 +1998,7 @@ xfs_attr3_leaf_unbalance(
struct xfs_attr_leafblock *tmp_leaf;
struct xfs_attr3_icleaf_hdr tmphdr;
tmp_leaf = kmem_zalloc(state->blocksize, KM_SLEEP);
tmp_leaf = kmem_zalloc(state->args->geo->blksize, KM_SLEEP);
/*
* Copy the header into the temp leaf so that all the stuff
@ -2020,35 +2011,39 @@ xfs_attr3_leaf_unbalance(
tmphdr.magic = savehdr.magic;
tmphdr.forw = savehdr.forw;
tmphdr.back = savehdr.back;
tmphdr.firstused = state->blocksize;
tmphdr.firstused = state->args->geo->blksize;
/* write the header to the temp buffer to initialise it */
xfs_attr3_leaf_hdr_to_disk(tmp_leaf, &tmphdr);
if (xfs_attr3_leaf_order(save_blk->bp, &savehdr,
drop_blk->bp, &drophdr)) {
xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
xfs_attr3_leaf_moveents(state->args,
drop_leaf, &drophdr, 0,
tmp_leaf, &tmphdr, 0,
drophdr.count, mp);
xfs_attr3_leaf_moveents(save_leaf, &savehdr, 0,
drophdr.count);
xfs_attr3_leaf_moveents(state->args,
save_leaf, &savehdr, 0,
tmp_leaf, &tmphdr, tmphdr.count,
savehdr.count, mp);
savehdr.count);
} else {
xfs_attr3_leaf_moveents(save_leaf, &savehdr, 0,
xfs_attr3_leaf_moveents(state->args,
save_leaf, &savehdr, 0,
tmp_leaf, &tmphdr, 0,
savehdr.count, mp);
xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
savehdr.count);
xfs_attr3_leaf_moveents(state->args,
drop_leaf, &drophdr, 0,
tmp_leaf, &tmphdr, tmphdr.count,
drophdr.count, mp);
drophdr.count);
}
memcpy(save_leaf, tmp_leaf, state->blocksize);
memcpy(save_leaf, tmp_leaf, state->args->geo->blksize);
savehdr = tmphdr; /* struct copy */
kmem_free(tmp_leaf);
}
xfs_attr3_leaf_hdr_to_disk(save_leaf, &savehdr);
xfs_trans_log_buf(state->args->trans, save_blk->bp, 0,
state->blocksize - 1);
state->args->geo->blksize - 1);
/*
* Copy out last hashval in each block for B-tree code.
@ -2094,7 +2089,7 @@ xfs_attr3_leaf_lookup_int(
leaf = bp->b_addr;
xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
entries = xfs_attr3_leaf_entryp(leaf);
ASSERT(ichdr.count < XFS_LBSIZE(args->dp->i_mount) / 8);
ASSERT(ichdr.count < args->geo->blksize / 8);
/*
* Binary search. (note: small blocks will skip this loop)
@ -2198,7 +2193,7 @@ xfs_attr3_leaf_getvalue(
leaf = bp->b_addr;
xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
ASSERT(ichdr.count < XFS_LBSIZE(args->dp->i_mount) / 8);
ASSERT(ichdr.count < args->geo->blksize / 8);
ASSERT(args->index < ichdr.count);
entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
@ -2249,14 +2244,14 @@ xfs_attr3_leaf_getvalue(
/*ARGSUSED*/
STATIC void
xfs_attr3_leaf_moveents(
struct xfs_da_args *args,
struct xfs_attr_leafblock *leaf_s,
struct xfs_attr3_icleaf_hdr *ichdr_s,
int start_s,
struct xfs_attr_leafblock *leaf_d,
struct xfs_attr3_icleaf_hdr *ichdr_d,
int start_d,
int count,
struct xfs_mount *mp)
int count)
{
struct xfs_attr_leaf_entry *entry_s;
struct xfs_attr_leaf_entry *entry_d;
@ -2276,10 +2271,10 @@ xfs_attr3_leaf_moveents(
ASSERT(ichdr_s->magic == XFS_ATTR_LEAF_MAGIC ||
ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC);
ASSERT(ichdr_s->magic == ichdr_d->magic);
ASSERT(ichdr_s->count > 0 && ichdr_s->count < XFS_LBSIZE(mp) / 8);
ASSERT(ichdr_s->count > 0 && ichdr_s->count < args->geo->blksize / 8);
ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s))
+ xfs_attr3_leaf_hdr_size(leaf_s));
ASSERT(ichdr_d->count < XFS_LBSIZE(mp) / 8);
ASSERT(ichdr_d->count < args->geo->blksize / 8);
ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d))
+ xfs_attr3_leaf_hdr_size(leaf_d));
@ -2331,11 +2326,11 @@ xfs_attr3_leaf_moveents(
entry_d->nameidx = cpu_to_be16(ichdr_d->firstused);
entry_d->flags = entry_s->flags;
ASSERT(be16_to_cpu(entry_d->nameidx) + tmp
<= XFS_LBSIZE(mp));
<= args->geo->blksize);
memmove(xfs_attr3_leaf_name(leaf_d, desti),
xfs_attr3_leaf_name(leaf_s, start_s + i), tmp);
ASSERT(be16_to_cpu(entry_s->nameidx) + tmp
<= XFS_LBSIZE(mp));
<= args->geo->blksize);
memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp);
ichdr_s->usedbytes -= tmp;
ichdr_d->usedbytes += tmp;
@ -2356,7 +2351,7 @@ xfs_attr3_leaf_moveents(
tmp = count * sizeof(xfs_attr_leaf_entry_t);
entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
ASSERT(((char *)entry_s + tmp) <=
((char *)leaf_s + XFS_LBSIZE(mp)));
((char *)leaf_s + args->geo->blksize));
memset(entry_s, 0, tmp);
} else {
/*
@ -2371,7 +2366,7 @@ xfs_attr3_leaf_moveents(
tmp = count * sizeof(xfs_attr_leaf_entry_t);
entry_s = &xfs_attr3_leaf_entryp(leaf_s)[ichdr_s->count];
ASSERT(((char *)entry_s + tmp) <=
((char *)leaf_s + XFS_LBSIZE(mp)));
((char *)leaf_s + args->geo->blksize));
memset(entry_s, 0, tmp);
}
@ -2439,22 +2434,21 @@ xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index)
* a "local" or a "remote" attribute.
*/
int
xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, int *local)
xfs_attr_leaf_newentsize(
struct xfs_da_args *args,
int *local)
{
int size;
int size;
size = xfs_attr_leaf_entsize_local(namelen, valuelen);
if (size < xfs_attr_leaf_entsize_local_max(blocksize)) {
if (local) {
size = xfs_attr_leaf_entsize_local(args->namelen, args->valuelen);
if (size < xfs_attr_leaf_entsize_local_max(args->geo->blksize)) {
if (local)
*local = 1;
}
} else {
size = xfs_attr_leaf_entsize_remote(namelen);
if (local) {
*local = 0;
}
return size;
}
return size;
if (local)
*local = 0;
return xfs_attr_leaf_entsize_remote(args->namelen);
}

View file

@ -96,8 +96,7 @@ int xfs_attr3_root_inactive(struct xfs_trans **trans, struct xfs_inode *dp);
xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_buf *bp, int *count);
int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp,
struct xfs_buf *leaf2_bp);
int xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize,
int *local);
int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local);
int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_daddr_t mappedbno,
struct xfs_buf **bpp);

View file

@ -444,6 +444,7 @@ xfs_attr3_leaf_list_int(
xfs_da_args_t args;
memset((char *)&args, 0, sizeof(args));
args.geo = context->dp->i_mount->m_attr_geo;
args.dp = context->dp;
args.whichfork = XFS_ATTR_FORK;
args.valuelen = valuelen;

View file

@ -68,7 +68,6 @@ xfs_attr3_rmt_blocks(
*/
static bool
xfs_attr3_rmt_hdr_ok(
struct xfs_mount *mp,
void *ptr,
xfs_ino_t ino,
uint32_t offset,
@ -126,6 +125,7 @@ xfs_attr3_rmt_read_verify(
char *ptr;
int len;
xfs_daddr_t bno;
int blksize = mp->m_attr_geo->blksize;
/* no verification of non-crc buffers */
if (!xfs_sb_version_hascrc(&mp->m_sb))
@ -134,21 +134,20 @@ xfs_attr3_rmt_read_verify(
ptr = bp->b_addr;
bno = bp->b_bn;
len = BBTOB(bp->b_length);
ASSERT(len >= XFS_LBSIZE(mp));
ASSERT(len >= blksize);
while (len > 0) {
if (!xfs_verify_cksum(ptr, XFS_LBSIZE(mp),
XFS_ATTR3_RMT_CRC_OFF)) {
if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) {
xfs_buf_ioerror(bp, EFSBADCRC);
break;
}
if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) {
if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
xfs_buf_ioerror(bp, EFSCORRUPTED);
break;
}
len -= XFS_LBSIZE(mp);
ptr += XFS_LBSIZE(mp);
bno += mp->m_bsize;
len -= blksize;
ptr += blksize;
bno += BTOBB(blksize);
}
if (bp->b_error)
@ -166,6 +165,7 @@ xfs_attr3_rmt_write_verify(
char *ptr;
int len;
xfs_daddr_t bno;
int blksize = mp->m_attr_geo->blksize;
/* no verification of non-crc buffers */
if (!xfs_sb_version_hascrc(&mp->m_sb))
@ -174,10 +174,10 @@ xfs_attr3_rmt_write_verify(
ptr = bp->b_addr;
bno = bp->b_bn;
len = BBTOB(bp->b_length);
ASSERT(len >= XFS_LBSIZE(mp));
ASSERT(len >= blksize);
while (len > 0) {
if (!xfs_attr3_rmt_verify(mp, ptr, XFS_LBSIZE(mp), bno)) {
if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) {
xfs_buf_ioerror(bp, EFSCORRUPTED);
xfs_verifier_error(bp);
return;
@ -188,11 +188,11 @@ xfs_attr3_rmt_write_verify(
rmt = (struct xfs_attr3_rmt_hdr *)ptr;
rmt->rm_lsn = cpu_to_be64(bip->bli_item.li_lsn);
}
xfs_update_cksum(ptr, XFS_LBSIZE(mp), XFS_ATTR3_RMT_CRC_OFF);
xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF);
len -= XFS_LBSIZE(mp);
ptr += XFS_LBSIZE(mp);
bno += mp->m_bsize;
len -= blksize;
ptr += blksize;
bno += BTOBB(blksize);
}
ASSERT(len == 0);
}
@ -241,17 +241,18 @@ xfs_attr_rmtval_copyout(
char *src = bp->b_addr;
xfs_daddr_t bno = bp->b_bn;
int len = BBTOB(bp->b_length);
int blksize = mp->m_attr_geo->blksize;
ASSERT(len >= XFS_LBSIZE(mp));
ASSERT(len >= blksize);
while (len > 0 && *valuelen > 0) {
int hdr_size = 0;
int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
byte_cnt = min(*valuelen, byte_cnt);
if (xfs_sb_version_hascrc(&mp->m_sb)) {
if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset,
if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset,
byte_cnt, bno)) {
xfs_alert(mp,
"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)",
@ -264,9 +265,9 @@ xfs_attr_rmtval_copyout(
memcpy(*dst, src + hdr_size, byte_cnt);
/* roll buffer forwards */
len -= XFS_LBSIZE(mp);
src += XFS_LBSIZE(mp);
bno += mp->m_bsize;
len -= blksize;
src += blksize;
bno += BTOBB(blksize);
/* roll attribute data forwards */
*valuelen -= byte_cnt;
@ -288,12 +289,13 @@ xfs_attr_rmtval_copyin(
char *dst = bp->b_addr;
xfs_daddr_t bno = bp->b_bn;
int len = BBTOB(bp->b_length);
int blksize = mp->m_attr_geo->blksize;
ASSERT(len >= XFS_LBSIZE(mp));
ASSERT(len >= blksize);
while (len > 0 && *valuelen > 0) {
int hdr_size;
int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize);
byte_cnt = min(*valuelen, byte_cnt);
hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset,
@ -305,17 +307,17 @@ xfs_attr_rmtval_copyin(
* If this is the last block, zero the remainder of it.
* Check that we are actually the last block, too.
*/
if (byte_cnt + hdr_size < XFS_LBSIZE(mp)) {
if (byte_cnt + hdr_size < blksize) {
ASSERT(*valuelen - byte_cnt == 0);
ASSERT(len == XFS_LBSIZE(mp));
ASSERT(len == blksize);
memset(dst + hdr_size + byte_cnt, 0,
XFS_LBSIZE(mp) - hdr_size - byte_cnt);
blksize - hdr_size - byte_cnt);
}
/* roll buffer forwards */
len -= XFS_LBSIZE(mp);
dst += XFS_LBSIZE(mp);
bno += mp->m_bsize;
len -= blksize;
dst += blksize;
bno += BTOBB(blksize);
/* roll attribute data forwards */
*valuelen -= byte_cnt;

View file

@ -66,8 +66,11 @@ static inline int xfs_lowbit64(__uint64_t v)
n = ffs(w);
} else { /* upper bits */
w = (__uint32_t)(v >> 32);
if (w && (n = ffs(w)))
n += 32;
if (w) {
n = ffs(w);
if (n)
n += 32;
}
}
return n - 1;
}

View file

@ -94,7 +94,7 @@ xfs_bmap_compute_maxlevels(
maxleafents = MAXAEXTNUM;
sz = XFS_BMDR_SPACE_CALC(MINABTPTRS);
}
maxrootrecs = xfs_bmdr_maxrecs(mp, sz, 0);
maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
minleafrecs = mp->m_bmap_dmnr[0];
minnoderecs = mp->m_bmap_dmnr[1];
maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
@ -233,7 +233,6 @@ xfs_default_attroffset(
*/
STATIC void
xfs_bmap_forkoff_reset(
xfs_mount_t *mp,
xfs_inode_t *ip,
int whichfork)
{
@ -905,7 +904,7 @@ xfs_bmap_local_to_extents_empty(
ASSERT(ifp->if_bytes == 0);
ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
xfs_bmap_forkoff_reset(ip, whichfork);
ifp->if_flags &= ~XFS_IFINLINE;
ifp->if_flags |= XFS_IFEXTENTS;
XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
@ -1099,10 +1098,11 @@ xfs_bmap_add_attrfork_local(
if (S_ISDIR(ip->i_d.di_mode)) {
memset(&dargs, 0, sizeof(dargs));
dargs.geo = ip->i_mount->m_dir_geo;
dargs.dp = ip;
dargs.firstblock = firstblock;
dargs.flist = flist;
dargs.total = ip->i_mount->m_dirblkfsbs;
dargs.total = dargs.geo->fsbcount;
dargs.whichfork = XFS_DATA_FORK;
dargs.trans = tp;
return xfs_dir2_sf_to_block(&dargs);
@ -1675,7 +1675,6 @@ xfs_bmap_isaeof(
*/
int
xfs_bmap_last_offset(
struct xfs_trans *tp,
struct xfs_inode *ip,
xfs_fileoff_t *last_block,
int whichfork)
@ -3517,6 +3516,67 @@ xfs_bmap_adjacent(
#undef ISVALID
}
static int
xfs_bmap_longest_free_extent(
struct xfs_trans *tp,
xfs_agnumber_t ag,
xfs_extlen_t *blen,
int *notinit)
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_perag *pag;
xfs_extlen_t longest;
int error = 0;
pag = xfs_perag_get(mp, ag);
if (!pag->pagf_init) {
error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK);
if (error)
goto out;
if (!pag->pagf_init) {
*notinit = 1;
goto out;
}
}
longest = xfs_alloc_longest_free_extent(mp, pag);
if (*blen < longest)
*blen = longest;
out:
xfs_perag_put(pag);
return error;
}
static void
xfs_bmap_select_minlen(
struct xfs_bmalloca *ap,
struct xfs_alloc_arg *args,
xfs_extlen_t *blen,
int notinit)
{
if (notinit || *blen < ap->minlen) {
/*
* Since we did a BUF_TRYLOCK above, it is possible that
* there is space for this request.
*/
args->minlen = ap->minlen;
} else if (*blen < args->maxlen) {
/*
* If the best seen length is less than the request length,
* use the best as the minimum.
*/
args->minlen = *blen;
} else {
/*
* Otherwise we've seen an extent as big as maxlen, use that
* as the minimum.
*/
args->minlen = args->maxlen;
}
}
STATIC int
xfs_bmap_btalloc_nullfb(
struct xfs_bmalloca *ap,
@ -3524,111 +3584,74 @@ xfs_bmap_btalloc_nullfb(
xfs_extlen_t *blen)
{
struct xfs_mount *mp = ap->ip->i_mount;
struct xfs_perag *pag;
xfs_agnumber_t ag, startag;
int notinit = 0;
int error;
if (ap->userdata && xfs_inode_is_filestream(ap->ip))
args->type = XFS_ALLOCTYPE_NEAR_BNO;
else
args->type = XFS_ALLOCTYPE_START_BNO;
args->type = XFS_ALLOCTYPE_START_BNO;
args->total = ap->total;
/*
* Search for an allocation group with a single extent large enough
* for the request. If one isn't found, then adjust the minimum
* allocation size to the largest space found.
*/
startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
if (startag == NULLAGNUMBER)
startag = ag = 0;
pag = xfs_perag_get(mp, ag);
while (*blen < args->maxlen) {
if (!pag->pagf_init) {
error = xfs_alloc_pagf_init(mp, args->tp, ag,
XFS_ALLOC_FLAG_TRYLOCK);
if (error) {
xfs_perag_put(pag);
return error;
}
}
error = xfs_bmap_longest_free_extent(args->tp, ag, blen,
&notinit);
if (error)
return error;
/*
* See xfs_alloc_fix_freelist...
*/
if (pag->pagf_init) {
xfs_extlen_t longest;
longest = xfs_alloc_longest_free_extent(mp, pag);
if (*blen < longest)
*blen = longest;
} else
notinit = 1;
if (xfs_inode_is_filestream(ap->ip)) {
if (*blen >= args->maxlen)
break;
if (ap->userdata) {
/*
* If startag is an invalid AG, we've
* come here once before and
* xfs_filestream_new_ag picked the
* best currently available.
*
* Don't continue looping, since we
* could loop forever.
*/
if (startag == NULLAGNUMBER)
break;
error = xfs_filestream_new_ag(ap, &ag);
xfs_perag_put(pag);
if (error)
return error;
/* loop again to set 'blen'*/
startag = NULLAGNUMBER;
pag = xfs_perag_get(mp, ag);
continue;
}
}
if (++ag == mp->m_sb.sb_agcount)
ag = 0;
if (ag == startag)
break;
xfs_perag_put(pag);
pag = xfs_perag_get(mp, ag);
}
xfs_perag_put(pag);
xfs_bmap_select_minlen(ap, args, blen, notinit);
return 0;
}
STATIC int
xfs_bmap_btalloc_filestreams(
struct xfs_bmalloca *ap,
struct xfs_alloc_arg *args,
xfs_extlen_t *blen)
{
struct xfs_mount *mp = ap->ip->i_mount;
xfs_agnumber_t ag;
int notinit = 0;
int error;
args->type = XFS_ALLOCTYPE_NEAR_BNO;
args->total = ap->total;
ag = XFS_FSB_TO_AGNO(mp, args->fsbno);
if (ag == NULLAGNUMBER)
ag = 0;
error = xfs_bmap_longest_free_extent(args->tp, ag, blen, &notinit);
if (error)
return error;
if (*blen < args->maxlen) {
error = xfs_filestream_new_ag(ap, &ag);
if (error)
return error;
error = xfs_bmap_longest_free_extent(args->tp, ag, blen,
&notinit);
if (error)
return error;
}
xfs_bmap_select_minlen(ap, args, blen, notinit);
/*
* Since the above loop did a BUF_TRYLOCK, it is
* possible that there is space for this request.
* Set the failure fallback case to look in the selected AG as stream
* may have moved.
*/
if (notinit || *blen < ap->minlen)
args->minlen = ap->minlen;
/*
* If the best seen length is less than the request
* length, use the best as the minimum.
*/
else if (*blen < args->maxlen)
args->minlen = *blen;
/*
* Otherwise we've seen an extent as big as maxlen,
* use that as the minimum.
*/
else
args->minlen = args->maxlen;
/*
* set the failure fallback case to look in the selected
* AG as the stream may have moved.
*/
if (xfs_inode_is_filestream(ap->ip))
ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
return 0;
}
@ -3708,7 +3731,15 @@ xfs_bmap_btalloc(
args.firstblock = *ap->firstblock;
blen = 0;
if (nullfb) {
error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
/*
* Search for an allocation group with a single extent large
* enough for the request. If one isn't found, then adjust
* the minimum allocation size to the largest space found.
*/
if (ap->userdata && xfs_inode_is_filestream(ap->ip))
error = xfs_bmap_btalloc_filestreams(ap, &args, &blen);
else
error = xfs_bmap_btalloc_nullfb(ap, &args, &blen);
if (error)
return error;
} else if (ap->flist->xbf_low) {

View file

@ -156,8 +156,8 @@ int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork);
int xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_fileoff_t *last_block, int whichfork);
int xfs_bmap_last_offset(struct xfs_trans *tp, struct xfs_inode *ip,
xfs_fileoff_t *unused, int whichfork);
int xfs_bmap_last_offset(struct xfs_inode *ip, xfs_fileoff_t *unused,
int whichfork);
int xfs_bmap_one_block(struct xfs_inode *ip, int whichfork);
int xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip,
int whichfork);

View file

@ -84,7 +84,7 @@ xfs_bmdr_to_bmbt(
rblock->bb_level = dblock->bb_level;
ASSERT(be16_to_cpu(rblock->bb_level) > 0);
rblock->bb_numrecs = dblock->bb_numrecs;
dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
@ -443,7 +443,7 @@ xfs_bmbt_to_bmdr(
ASSERT(rblock->bb_level != 0);
dblock->bb_level = rblock->bb_level;
dblock->bb_numrecs = rblock->bb_numrecs;
dmxr = xfs_bmdr_maxrecs(mp, dblocklen, 0);
dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
tkp = XFS_BMDR_KEY_ADDR(dblock, 1);
fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
@ -519,7 +519,6 @@ xfs_bmbt_alloc_block(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *start,
union xfs_btree_ptr *new,
int length,
int *stat)
{
xfs_alloc_arg_t args; /* block allocation args */
@ -672,8 +671,7 @@ xfs_bmbt_get_dmaxrecs(
{
if (level != cur->bc_nlevels - 1)
return cur->bc_mp->m_bmap_dmxr[level != 0];
return xfs_bmdr_maxrecs(cur->bc_mp, cur->bc_private.b.forksize,
level == 0);
return xfs_bmdr_maxrecs(cur->bc_private.b.forksize, level == 0);
}
STATIC void
@ -914,7 +912,6 @@ xfs_bmbt_maxrecs(
*/
int
xfs_bmdr_maxrecs(
struct xfs_mount *mp,
int blocklen,
int leaf)
{

View file

@ -130,7 +130,7 @@ extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int,
xfs_bmdr_block_t *, int);
extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf);
extern int xfs_bmdr_maxrecs(int blocklen, int leaf);
extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,

View file

@ -258,14 +258,23 @@ xfs_bmapi_allocate_worker(
struct xfs_bmalloca *args = container_of(work,
struct xfs_bmalloca, work);
unsigned long pflags;
unsigned long new_pflags = PF_FSTRANS;
/* we are in a transaction context here */
current_set_flags_nested(&pflags, PF_FSTRANS);
/*
* we are in a transaction context here, but may also be doing work
* in kswapd context, and hence we may need to inherit that state
* temporarily to ensure that we don't block waiting for memory reclaim
* in any way.
*/
if (args->kswapd)
new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
current_set_flags_nested(&pflags, new_pflags);
args->result = __xfs_bmapi_allocate(args);
complete(args->done);
current_restore_flags_nested(&pflags, PF_FSTRANS);
current_restore_flags_nested(&pflags, new_pflags);
}
/*
@ -284,6 +293,7 @@ xfs_bmapi_allocate(
args->done = &done;
args->kswapd = current_is_kswapd();
INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker);
queue_work(xfs_alloc_wq, &args->work);
wait_for_completion(&done);
@ -1519,7 +1529,6 @@ xfs_collapse_file_space(
while (!error && !done) {
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
tp->t_flags |= XFS_TRANS_RESERVE;
/*
* We would need to reserve permanent block for transaction.
* This will come into picture when after shifting extent into
@ -1529,7 +1538,6 @@ xfs_collapse_file_space(
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
XFS_DIOSTRAT_SPACE_RES(mp, 0), 0);
if (error) {
ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
xfs_trans_cancel(tp, 0);
break;
}

View file

@ -50,12 +50,13 @@ struct xfs_bmalloca {
xfs_extlen_t total; /* total blocks needed for xaction */
xfs_extlen_t minlen; /* minimum allocation size (blocks) */
xfs_extlen_t minleft; /* amount must be left after alloc */
char eof; /* set if allocating past last extent */
char wasdel; /* replacing a delayed allocation */
char userdata;/* set if is user data */
char aeof; /* allocated space at eof */
char conv; /* overwriting unwritten extents */
char stack_switch;
bool eof; /* set if allocating past last extent */
bool wasdel; /* replacing a delayed allocation */
bool userdata;/* set if is user data */
bool aeof; /* allocated space at eof */
bool conv; /* overwriting unwritten extents */
bool stack_switch;
bool kswapd; /* allocation in kswapd context */
int flags;
struct completion *done;
struct work_struct work;

View file

@ -43,9 +43,10 @@ kmem_zone_t *xfs_btree_cur_zone;
* Btree magic numbers.
*/
static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = {
{ XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC },
{ XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, XFS_BMAP_MAGIC, XFS_IBT_MAGIC,
XFS_FIBT_MAGIC },
{ XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC,
XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC }
XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC }
};
#define xfs_btree_magic(cur) \
xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum]
@ -552,14 +553,11 @@ xfs_btree_get_bufl(
xfs_fsblock_t fsbno, /* file system block number */
uint lock) /* lock flags for get_buf */
{
xfs_buf_t *bp; /* buffer pointer (return value) */
xfs_daddr_t d; /* real disk block address */
ASSERT(fsbno != NULLFSBLOCK);
d = XFS_FSB_TO_DADDR(mp, fsbno);
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
ASSERT(!xfs_buf_geterror(bp));
return bp;
return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
}
/*
@ -574,15 +572,12 @@ xfs_btree_get_bufs(
xfs_agblock_t agbno, /* allocation group block number */
uint lock) /* lock flags for get_buf */
{
xfs_buf_t *bp; /* buffer pointer (return value) */
xfs_daddr_t d; /* real disk block address */
ASSERT(agno != NULLAGNUMBER);
ASSERT(agbno != NULLAGBLOCK);
d = XFS_AGB_TO_DADDR(mp, agno, agbno);
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
ASSERT(!xfs_buf_geterror(bp));
return bp;
return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock);
}
/*
@ -722,7 +717,6 @@ xfs_btree_read_bufl(
mp->m_bsize, lock, &bp, ops);
if (error)
return error;
ASSERT(!xfs_buf_geterror(bp));
if (bp)
xfs_buf_set_ref(bp, refval);
*bpp = bp;
@ -1115,6 +1109,7 @@ xfs_btree_set_refs(
xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF);
break;
case XFS_BTNUM_INO:
case XFS_BTNUM_FINO:
xfs_buf_set_ref(bp, XFS_INO_BTREE_REF);
break;
case XFS_BTNUM_BMAP:
@ -1159,7 +1154,6 @@ STATIC int
xfs_btree_read_buf_block(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *ptr,
int level,
int flags,
struct xfs_btree_block **block,
struct xfs_buf **bpp)
@ -1178,7 +1172,6 @@ xfs_btree_read_buf_block(
if (error)
return error;
ASSERT(!xfs_buf_geterror(*bpp));
xfs_btree_set_refs(cur, *bpp);
*block = XFS_BUF_TO_BLOCK(*bpp);
return 0;
@ -1517,8 +1510,8 @@ xfs_btree_increment(
union xfs_btree_ptr *ptrp;
ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block);
error = xfs_btree_read_buf_block(cur, ptrp, --lev,
0, &block, &bp);
--lev;
error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp);
if (error)
goto error0;
@ -1616,8 +1609,8 @@ xfs_btree_decrement(
union xfs_btree_ptr *ptrp;
ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block);
error = xfs_btree_read_buf_block(cur, ptrp, --lev,
0, &block, &bp);
--lev;
error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp);
if (error)
goto error0;
xfs_btree_setbuf(cur, lev, bp);
@ -1667,7 +1660,7 @@ xfs_btree_lookup_get_block(
return 0;
}
error = xfs_btree_read_buf_block(cur, pp, level, 0, blkp, &bp);
error = xfs_btree_read_buf_block(cur, pp, 0, blkp, &bp);
if (error)
return error;
@ -2018,7 +2011,7 @@ xfs_btree_lshift(
goto out0;
/* Set up the left neighbor as "left". */
error = xfs_btree_read_buf_block(cur, &lptr, level, 0, &left, &lbp);
error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp);
if (error)
goto error0;
@ -2202,7 +2195,7 @@ xfs_btree_rshift(
goto out0;
/* Set up the right neighbor as "right". */
error = xfs_btree_read_buf_block(cur, &rptr, level, 0, &right, &rbp);
error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp);
if (error)
goto error0;
@ -2372,7 +2365,7 @@ xfs_btree_split(
xfs_btree_buf_to_ptr(cur, lbp, &lptr);
/* Allocate the new block. If we can't do it, we're toast. Give up. */
error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, 1, stat);
error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, stat);
if (error)
goto error0;
if (*stat == 0)
@ -2470,7 +2463,7 @@ xfs_btree_split(
* point back to right instead of to left.
*/
if (!xfs_btree_ptr_is_null(cur, &rrptr)) {
error = xfs_btree_read_buf_block(cur, &rrptr, level,
error = xfs_btree_read_buf_block(cur, &rrptr,
0, &rrblock, &rrbp);
if (error)
goto error0;
@ -2545,7 +2538,7 @@ xfs_btree_new_iroot(
pp = xfs_btree_ptr_addr(cur, 1, block);
/* Allocate the new block. If we can't do it, we're toast. Give up. */
error = cur->bc_ops->alloc_block(cur, pp, &nptr, 1, stat);
error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat);
if (error)
goto error0;
if (*stat == 0) {
@ -2649,7 +2642,7 @@ xfs_btree_new_root(
cur->bc_ops->init_ptr_from_cur(cur, &rptr);
/* Allocate the new block. If we can't do it, we're toast. Give up. */
error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, 1, stat);
error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, stat);
if (error)
goto error0;
if (*stat == 0)
@ -2684,8 +2677,7 @@ xfs_btree_new_root(
lbp = bp;
xfs_btree_buf_to_ptr(cur, lbp, &lptr);
left = block;
error = xfs_btree_read_buf_block(cur, &rptr,
cur->bc_nlevels - 1, 0, &right, &rbp);
error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp);
if (error)
goto error0;
bp = rbp;
@ -2696,8 +2688,7 @@ xfs_btree_new_root(
xfs_btree_buf_to_ptr(cur, rbp, &rptr);
right = block;
xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB);
error = xfs_btree_read_buf_block(cur, &lptr,
cur->bc_nlevels - 1, 0, &left, &lbp);
error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp);
if (error)
goto error0;
bp = lbp;
@ -3649,8 +3640,7 @@ xfs_btree_delrec(
rptr = cptr;
right = block;
rbp = bp;
error = xfs_btree_read_buf_block(cur, &lptr, level,
0, &left, &lbp);
error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp);
if (error)
goto error0;
@ -3667,8 +3657,7 @@ xfs_btree_delrec(
lptr = cptr;
left = block;
lbp = bp;
error = xfs_btree_read_buf_block(cur, &rptr, level,
0, &right, &rbp);
error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp);
if (error)
goto error0;
@ -3740,8 +3729,7 @@ xfs_btree_delrec(
/* If there is a right sibling, point it to the remaining block. */
xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB);
if (!xfs_btree_ptr_is_null(cur, &cptr)) {
error = xfs_btree_read_buf_block(cur, &cptr, level,
0, &rrblock, &rrbp);
error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp);
if (error)
goto error0;
xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB);

View file

@ -62,6 +62,7 @@ union xfs_btree_rec {
#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi)
#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi)
#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi)
#define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi)
/*
* For logging record fields.
@ -92,6 +93,7 @@ do { \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \
case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
@ -105,6 +107,7 @@ do { \
case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
@ -129,7 +132,7 @@ struct xfs_btree_ops {
int (*alloc_block)(struct xfs_btree_cur *cur,
union xfs_btree_ptr *start_bno,
union xfs_btree_ptr *new_bno,
int length, int *stat);
int *stat);
int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp);
/* update last record information */

View file

@ -216,8 +216,7 @@ _xfs_buf_alloc(
STATIC int
_xfs_buf_get_pages(
xfs_buf_t *bp,
int page_count,
xfs_buf_flags_t flags)
int page_count)
{
/* Make sure that we have a page list */
if (bp->b_pages == NULL) {
@ -330,7 +329,7 @@ xfs_buf_allocate_memory(
end = (BBTOB(bp->b_maps[0].bm_bn + bp->b_length) + PAGE_SIZE - 1)
>> PAGE_SHIFT;
page_count = end - start;
error = _xfs_buf_get_pages(bp, page_count, flags);
error = _xfs_buf_get_pages(bp, page_count);
if (unlikely(error))
return error;
@ -778,7 +777,7 @@ xfs_buf_associate_memory(
bp->b_pages = NULL;
bp->b_addr = mem;
rval = _xfs_buf_get_pages(bp, page_count, 0);
rval = _xfs_buf_get_pages(bp, page_count);
if (rval)
return rval;
@ -811,7 +810,7 @@ xfs_buf_get_uncached(
goto fail;
page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT;
error = _xfs_buf_get_pages(bp, page_count, 0);
error = _xfs_buf_get_pages(bp, page_count);
if (error)
goto fail_free_buf;
@ -1615,7 +1614,6 @@ xfs_free_buftarg(
int
xfs_setsize_buftarg(
xfs_buftarg_t *btp,
unsigned int blocksize,
unsigned int sectorsize)
{
/* Set up metadata sector size info */
@ -1650,16 +1648,13 @@ xfs_setsize_buftarg_early(
xfs_buftarg_t *btp,
struct block_device *bdev)
{
return xfs_setsize_buftarg(btp, PAGE_SIZE,
bdev_logical_block_size(bdev));
return xfs_setsize_buftarg(btp, bdev_logical_block_size(bdev));
}
xfs_buftarg_t *
xfs_alloc_buftarg(
struct xfs_mount *mp,
struct block_device *bdev,
int external,
const char *fsname)
struct block_device *bdev)
{
xfs_buftarg_t *btp;

View file

@ -298,11 +298,6 @@ extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
extern int xfs_bioerror_relse(struct xfs_buf *);
static inline int xfs_buf_geterror(xfs_buf_t *bp)
{
return bp ? bp->b_error : ENOMEM;
}
/* Buffer Utility Routines */
extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
@ -387,10 +382,10 @@ xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset)
* Handling of buftargs.
*/
extern xfs_buftarg_t *xfs_alloc_buftarg(struct xfs_mount *,
struct block_device *, int, const char *);
struct block_device *);
extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *);
extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int);
#define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev)
#define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev)

View file

@ -812,7 +812,6 @@ xfs_buf_item_init(
*/
static void
xfs_buf_item_log_segment(
struct xfs_buf_log_item *bip,
uint first,
uint last,
uint *map)
@ -920,7 +919,7 @@ xfs_buf_item_log(
if (end > last)
end = last;
xfs_buf_item_log_segment(bip, first, end,
xfs_buf_item_log_segment(first, end,
&bip->bli_formats[i].blf_data_map[0]);
start += bp->b_maps[i].bm_len;
@ -1053,7 +1052,7 @@ xfs_buf_iodone_callbacks(
static ulong lasttime;
static xfs_buftarg_t *lasttarg;
if (likely(!xfs_buf_geterror(bp)))
if (likely(!bp->b_error))
goto do_callbacks;
/*

View file

@ -167,8 +167,8 @@ xfs_da3_node_verify(
* we don't know if the node is for and attribute or directory tree,
* so only fail if the count is outside both bounds
*/
if (ichdr.count > mp->m_dir_node_ents &&
ichdr.count > mp->m_attr_node_ents)
if (ichdr.count > mp->m_dir_geo->node_ents &&
ichdr.count > mp->m_attr_geo->node_ents)
return false;
/* XXX: hash order check? */
@ -598,7 +598,7 @@ xfs_da3_root_split(
* Set up the new root node.
*/
error = xfs_da3_node_create(args,
(args->whichfork == XFS_DATA_FORK) ? mp->m_dirleafblk : 0,
(args->whichfork == XFS_DATA_FORK) ? args->geo->leafblk : 0,
level + 1, &bp, args->whichfork);
if (error)
return error;
@ -616,10 +616,10 @@ xfs_da3_root_split(
#ifdef DEBUG
if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
ASSERT(blk1->blkno >= mp->m_dirleafblk &&
blk1->blkno < mp->m_dirfreeblk);
ASSERT(blk2->blkno >= mp->m_dirleafblk &&
blk2->blkno < mp->m_dirfreeblk);
ASSERT(blk1->blkno >= args->geo->leafblk &&
blk1->blkno < args->geo->freeblk);
ASSERT(blk2->blkno >= args->geo->leafblk &&
blk2->blkno < args->geo->freeblk);
}
#endif
@ -663,7 +663,7 @@ xfs_da3_node_split(
/*
* Do we have to split the node?
*/
if (nodehdr.count + newcount > state->node_ents) {
if (nodehdr.count + newcount > state->args->geo->node_ents) {
/*
* Allocate a new node, add to the doubly linked chain of
* nodes, then move some of our excess entries into it.
@ -894,8 +894,8 @@ xfs_da3_node_add(
ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count);
ASSERT(newblk->blkno != 0);
if (state->args->whichfork == XFS_DATA_FORK)
ASSERT(newblk->blkno >= state->mp->m_dirleafblk &&
newblk->blkno < state->mp->m_dirfreeblk);
ASSERT(newblk->blkno >= state->args->geo->leafblk &&
newblk->blkno < state->args->geo->freeblk);
/*
* We may need to make some room before we insert the new node.
@ -1089,14 +1089,15 @@ xfs_da3_root_join(
* that could occur. For dir3 blocks we also need to update the block
* number in the buffer header.
*/
memcpy(root_blk->bp->b_addr, bp->b_addr, state->blocksize);
memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize);
root_blk->bp->b_ops = bp->b_ops;
xfs_trans_buf_copy_type(root_blk->bp, bp);
if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) {
struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr;
da3->blkno = cpu_to_be64(root_blk->bp->b_bn);
}
xfs_trans_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1);
xfs_trans_log_buf(args->trans, root_blk->bp, 0,
args->geo->blksize - 1);
error = xfs_da_shrink_inode(args, child, bp);
return(error);
}
@ -1139,7 +1140,7 @@ xfs_da3_node_toosmall(
info = blk->bp->b_addr;
node = (xfs_da_intnode_t *)info;
dp->d_ops->node_hdr_from_disk(&nodehdr, node);
if (nodehdr.count > (state->node_ents >> 1)) {
if (nodehdr.count > (state->args->geo->node_ents >> 1)) {
*action = 0; /* blk over 50%, don't try to join */
return(0); /* blk over 50%, don't try to join */
}
@ -1176,8 +1177,8 @@ xfs_da3_node_toosmall(
* We prefer coalescing with the lower numbered sibling so as
* to shrink a directory over time.
*/
count = state->node_ents;
count -= state->node_ents >> 2;
count = state->args->geo->node_ents;
count -= state->args->geo->node_ents >> 2;
count -= nodehdr.count;
/* start with smaller blk num */
@ -1472,7 +1473,7 @@ xfs_da3_node_lookup_int(
* Descend thru the B-tree searching each level for the right
* node to use, until the right hashval is found.
*/
blkno = (args->whichfork == XFS_DATA_FORK)? state->mp->m_dirleafblk : 0;
blkno = (args->whichfork == XFS_DATA_FORK)? args->geo->leafblk : 0;
for (blk = &state->path.blk[0], state->path.active = 1;
state->path.active <= XFS_DA_NODE_MAXDEPTH;
blk++, state->path.active++) {
@ -2090,20 +2091,12 @@ xfs_da_grow_inode(
xfs_dablk_t *new_blkno)
{
xfs_fileoff_t bno;
int count;
int error;
trace_xfs_da_grow_inode(args);
if (args->whichfork == XFS_DATA_FORK) {
bno = args->dp->i_mount->m_dirleafblk;
count = args->dp->i_mount->m_dirblkfsbs;
} else {
bno = 0;
count = 1;
}
error = xfs_da_grow_inode_int(args, &bno, count);
bno = args->geo->leafblk;
error = xfs_da_grow_inode_int(args, &bno, args->geo->fsbcount);
if (!error)
*new_blkno = (xfs_dablk_t)bno;
return error;
@ -2158,7 +2151,7 @@ xfs_da3_swap_lastblock(
w = args->whichfork;
ASSERT(w == XFS_DATA_FORK);
mp = dp->i_mount;
lastoff = mp->m_dirfreeblk;
lastoff = args->geo->freeblk;
error = xfs_bmap_last_before(tp, dp, &lastoff, w);
if (error)
return error;
@ -2170,15 +2163,15 @@ xfs_da3_swap_lastblock(
/*
* Read the last block in the btree space.
*/
last_blkno = (xfs_dablk_t)lastoff - mp->m_dirblkfsbs;
last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount;
error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w);
if (error)
return error;
/*
* Copy the last block into the dead buffer and log it.
*/
memcpy(dead_buf->b_addr, last_buf->b_addr, mp->m_dirblksize);
xfs_trans_log_buf(tp, dead_buf, 0, mp->m_dirblksize - 1);
memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize);
xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1);
dead_info = dead_buf->b_addr;
/*
* Get values from the moved block.
@ -2247,7 +2240,7 @@ xfs_da3_swap_lastblock(
sizeof(sib_info->back)));
sib_buf = NULL;
}
par_blkno = mp->m_dirleafblk;
par_blkno = args->geo->leafblk;
level = -1;
/*
* Walk down the tree looking for the parent of the moved block.
@ -2357,10 +2350,7 @@ xfs_da_shrink_inode(
w = args->whichfork;
tp = args->trans;
mp = dp->i_mount;
if (w == XFS_DATA_FORK)
count = mp->m_dirblkfsbs;
else
count = 1;
count = args->geo->fsbcount;
for (;;) {
/*
* Remove extents. If we get ENOSPC for a dir we have to move
@ -2462,7 +2452,6 @@ xfs_buf_map_from_irec(
*/
static int
xfs_dabuf_map(
struct xfs_trans *trans,
struct xfs_inode *dp,
xfs_dablk_t bno,
xfs_daddr_t mappedbno,
@ -2480,7 +2469,10 @@ xfs_dabuf_map(
ASSERT(map && *map);
ASSERT(*nmaps == 1);
nfsb = (whichfork == XFS_DATA_FORK) ? mp->m_dirblkfsbs : 1;
if (whichfork == XFS_DATA_FORK)
nfsb = mp->m_dir_geo->fsbcount;
else
nfsb = mp->m_attr_geo->fsbcount;
/*
* Caller doesn't have a mapping. -2 means don't complain
@ -2558,7 +2550,7 @@ xfs_da_get_buf(
*bpp = NULL;
mapp = &map;
nmap = 1;
error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
&mapp, &nmap);
if (error) {
/* mapping a hole is not an error, but we don't continue */
@ -2606,7 +2598,7 @@ xfs_da_read_buf(
*bpp = NULL;
mapp = &map;
nmap = 1;
error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
&mapp, &nmap);
if (error) {
/* mapping a hole is not an error, but we don't continue */
@ -2625,47 +2617,6 @@ xfs_da_read_buf(
xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF);
else
xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF);
/*
* This verification code will be moved to a CRC verification callback
* function so just leave it here unchanged until then.
*/
{
xfs_dir2_data_hdr_t *hdr = bp->b_addr;
xfs_dir2_free_t *free = bp->b_addr;
xfs_da_blkinfo_t *info = bp->b_addr;
uint magic, magic1;
struct xfs_mount *mp = dp->i_mount;
magic = be16_to_cpu(info->magic);
magic1 = be32_to_cpu(hdr->magic);
if (unlikely(
XFS_TEST_ERROR((magic != XFS_DA_NODE_MAGIC) &&
(magic != XFS_DA3_NODE_MAGIC) &&
(magic != XFS_ATTR_LEAF_MAGIC) &&
(magic != XFS_ATTR3_LEAF_MAGIC) &&
(magic != XFS_DIR2_LEAF1_MAGIC) &&
(magic != XFS_DIR3_LEAF1_MAGIC) &&
(magic != XFS_DIR2_LEAFN_MAGIC) &&
(magic != XFS_DIR3_LEAFN_MAGIC) &&
(magic1 != XFS_DIR2_BLOCK_MAGIC) &&
(magic1 != XFS_DIR3_BLOCK_MAGIC) &&
(magic1 != XFS_DIR2_DATA_MAGIC) &&
(magic1 != XFS_DIR3_DATA_MAGIC) &&
(free->hdr.magic !=
cpu_to_be32(XFS_DIR2_FREE_MAGIC)) &&
(free->hdr.magic !=
cpu_to_be32(XFS_DIR3_FREE_MAGIC)),
mp, XFS_ERRTAG_DA_READ_BUF,
XFS_RANDOM_DA_READ_BUF))) {
trace_xfs_da_btree_corrupt(bp, _RET_IP_);
XFS_CORRUPTION_ERROR("xfs_da_do_buf(2)",
XFS_ERRLEVEL_LOW, mp, info);
error = XFS_ERROR(EFSCORRUPTED);
xfs_trans_brelse(trans, bp);
goto out_free;
}
}
*bpp = bp;
out_free:
if (mapp != &map)
@ -2679,7 +2630,6 @@ xfs_da_read_buf(
*/
xfs_daddr_t
xfs_da_reada_buf(
struct xfs_trans *trans,
struct xfs_inode *dp,
xfs_dablk_t bno,
xfs_daddr_t mappedbno,
@ -2693,7 +2643,7 @@ xfs_da_reada_buf(
mapp = &map;
nmap = 1;
error = xfs_dabuf_map(trans, dp, bno, mappedbno, whichfork,
error = xfs_dabuf_map(dp, bno, mappedbno, whichfork,
&mapp, &nmap);
if (error) {
/* mapping a hole is not an error, but we don't continue */

View file

@ -25,6 +25,23 @@ struct xfs_trans;
struct zone;
struct xfs_dir_ops;
/*
* Directory/attribute geometry information. There will be one of these for each
* data fork type, and it will be passed around via the xfs_da_args. Global
* structures will be attached to the xfs_mount.
*/
struct xfs_da_geometry {
int blksize; /* da block size in bytes */
int fsbcount; /* da block size in filesystem blocks */
uint8_t fsblog; /* log2 of _filesystem_ block size */
uint8_t blklog; /* log2 of da block size */
uint node_ents; /* # of entries in a danode */
int magicpct; /* 37% of block size in bytes */
xfs_dablk_t datablk; /* blockno of dir data v2 */
xfs_dablk_t leafblk; /* blockno of leaf data v2 */
xfs_dablk_t freeblk; /* blockno of free data v2 */
};
/*========================================================================
* Btree searching and modification structure definitions.
*========================================================================*/
@ -42,6 +59,7 @@ enum xfs_dacmp {
* Structure to ease passing around component names.
*/
typedef struct xfs_da_args {
struct xfs_da_geometry *geo; /* da block geometry */
const __uint8_t *name; /* string (maybe not NULL terminated) */
int namelen; /* length of string (maybe no NULL) */
__uint8_t filetype; /* filetype of inode for directories */
@ -110,8 +128,6 @@ typedef struct xfs_da_state_path {
typedef struct xfs_da_state {
xfs_da_args_t *args; /* filename arguments */
struct xfs_mount *mp; /* filesystem mount point */
unsigned int blocksize; /* logical block size */
unsigned int node_ents; /* how many entries in danode */
xfs_da_state_path_t path; /* search/split paths */
xfs_da_state_path_t altpath; /* alternate path for join */
unsigned char inleaf; /* insert into 1->lf, 0->splf */
@ -185,9 +201,9 @@ int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_daddr_t mappedbno,
struct xfs_buf **bpp, int whichfork,
const struct xfs_buf_ops *ops);
xfs_daddr_t xfs_da_reada_buf(struct xfs_trans *trans, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_daddr_t mapped_bno,
int whichfork, const struct xfs_buf_ops *ops);
xfs_daddr_t xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno,
xfs_daddr_t mapped_bno, int whichfork,
const struct xfs_buf_ops *ops);
int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno,
struct xfs_buf *dead_buf);

View file

@ -26,8 +26,10 @@
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_inode.h"
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
/*
* Shortform directory ops
@ -425,9 +427,9 @@ xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr)
* Directory Leaf block operations
*/
static int
xfs_dir2_max_leaf_ents(struct xfs_mount *mp)
xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo)
{
return (mp->m_dirblksize - sizeof(struct xfs_dir2_leaf_hdr)) /
return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) /
(uint)sizeof(struct xfs_dir2_leaf_entry);
}
@ -438,9 +440,9 @@ xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp)
}
static int
xfs_dir3_max_leaf_ents(struct xfs_mount *mp)
xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo)
{
return (mp->m_dirblksize - sizeof(struct xfs_dir3_leaf_hdr)) /
return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) /
(uint)sizeof(struct xfs_dir2_leaf_entry);
}
@ -591,9 +593,9 @@ xfs_da3_node_hdr_to_disk(
* Directory free space block operations
*/
static int
xfs_dir2_free_max_bests(struct xfs_mount *mp)
xfs_dir2_free_max_bests(struct xfs_da_geometry *geo)
{
return (mp->m_dirblksize - sizeof(struct xfs_dir2_free_hdr)) /
return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) /
sizeof(xfs_dir2_data_off_t);
}
@ -607,24 +609,25 @@ xfs_dir2_free_bests_p(struct xfs_dir2_free *free)
* Convert data space db to the corresponding free db.
*/
static xfs_dir2_db_t
xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
{
return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir2_free_max_bests(mp);
return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) +
(db / xfs_dir2_free_max_bests(geo));
}
/*
* Convert data space db to the corresponding index in a free db.
*/
static int
xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
{
return db % xfs_dir2_free_max_bests(mp);
return db % xfs_dir2_free_max_bests(geo);
}
static int
xfs_dir3_free_max_bests(struct xfs_mount *mp)
xfs_dir3_free_max_bests(struct xfs_da_geometry *geo)
{
return (mp->m_dirblksize - sizeof(struct xfs_dir3_free_hdr)) /
return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) /
sizeof(xfs_dir2_data_off_t);
}
@ -638,18 +641,19 @@ xfs_dir3_free_bests_p(struct xfs_dir2_free *free)
* Convert data space db to the corresponding free db.
*/
static xfs_dir2_db_t
xfs_dir3_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
{
return XFS_DIR2_FREE_FIRSTDB(mp) + db / xfs_dir3_free_max_bests(mp);
return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) +
(db / xfs_dir3_free_max_bests(geo));
}
/*
* Convert data space db to the corresponding index in a free db.
*/
static int
xfs_dir3_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
{
return db % xfs_dir3_free_max_bests(mp);
return db % xfs_dir3_free_max_bests(geo);
}
static void

View file

@ -19,10 +19,6 @@
#ifndef __XFS_DA_FORMAT_H__
#define __XFS_DA_FORMAT_H__
/*========================================================================
* Directory Structure when greater than XFS_LBSIZE(mp) bytes.
*========================================================================*/
/*
* This structure is common to both leaf nodes and non-leaf nodes in the Btree.
*
@ -122,8 +118,6 @@ struct xfs_da3_icnode_hdr {
__uint16_t level;
};
#define XFS_LBSIZE(mp) (mp)->m_sb.sb_blocksize
/*
* Directory version 2.
*
@ -330,8 +324,6 @@ xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr)
#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG))
#define XFS_DIR2_DATA_SPACE 0
#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_DATA_FIRSTDB(mp) \
xfs_dir2_byte_to_db(mp, XFS_DIR2_DATA_OFFSET)
/*
* Describe a free area in the data block.
@ -456,8 +448,6 @@ xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup)
*/
#define XFS_DIR2_LEAF_SPACE 1
#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_LEAF_FIRSTDB(mp) \
xfs_dir2_byte_to_db(mp, XFS_DIR2_LEAF_OFFSET)
/*
* Leaf block header.
@ -513,17 +503,6 @@ struct xfs_dir3_leaf {
#define XFS_DIR3_LEAF_CRC_OFF offsetof(struct xfs_dir3_leaf_hdr, info.crc)
/*
* Get address of the bestcount field in the single-leaf block.
*/
static inline struct xfs_dir2_leaf_tail *
xfs_dir2_leaf_tail_p(struct xfs_mount *mp, struct xfs_dir2_leaf *lp)
{
return (struct xfs_dir2_leaf_tail *)
((char *)lp + mp->m_dirblksize -
sizeof(struct xfs_dir2_leaf_tail));
}
/*
* Get address of the bests array in the single-leaf block.
*/
@ -533,123 +512,6 @@ xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp)
return (__be16 *)ltp - be32_to_cpu(ltp->bestcount);
}
/*
* DB blocks here are logical directory block numbers, not filesystem blocks.
*/
/*
* Convert dataptr to byte in file space
*/
static inline xfs_dir2_off_t
xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
}
/*
* Convert byte in file space to dataptr. It had better be aligned.
*/
static inline xfs_dir2_dataptr_t
xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by)
{
return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG);
}
/*
* Convert byte in space to (DB) block
*/
static inline xfs_dir2_db_t
xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by)
{
return (xfs_dir2_db_t)
(by >> (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog));
}
/*
* Convert dataptr to a block number
*/
static inline xfs_dir2_db_t
xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(mp, dp));
}
/*
* Convert byte in space to offset in a block
*/
static inline xfs_dir2_data_aoff_t
xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by)
{
return (xfs_dir2_data_aoff_t)(by &
((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) - 1));
}
/*
* Convert dataptr to a byte offset in a block
*/
static inline xfs_dir2_data_aoff_t
xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(mp, dp));
}
/*
* Convert block and offset to byte in space
*/
static inline xfs_dir2_off_t
xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
{
return ((xfs_dir2_off_t)db <<
(mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) + o;
}
/*
* Convert block (DB) to block (dablk)
*/
static inline xfs_dablk_t
xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db)
{
return (xfs_dablk_t)(db << mp->m_sb.sb_dirblklog);
}
/*
* Convert byte in space to (DA) block
*/
static inline xfs_dablk_t
xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by)
{
return xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, by));
}
/*
* Convert block and offset to dataptr
*/
static inline xfs_dir2_dataptr_t
xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
{
return xfs_dir2_byte_to_dataptr(mp, xfs_dir2_db_off_to_byte(mp, db, o));
}
/*
* Convert block (dablk) to block (DB)
*/
static inline xfs_dir2_db_t
xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da)
{
return (xfs_dir2_db_t)(da >> mp->m_sb.sb_dirblklog);
}
/*
* Convert block (dablk) to byte offset in space
*/
static inline xfs_dir2_off_t
xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da)
{
return xfs_dir2_db_off_to_byte(mp, xfs_dir2_da_to_db(mp, da), 0);
}
/*
* Free space block defintions for the node format.
*/
@ -659,8 +521,6 @@ xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da)
*/
#define XFS_DIR2_FREE_SPACE 2
#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_FREE_FIRSTDB(mp) \
xfs_dir2_byte_to_db(mp, XFS_DIR2_FREE_OFFSET)
typedef struct xfs_dir2_free_hdr {
__be32 magic; /* XFS_DIR2_FREE_MAGIC */
@ -735,16 +595,6 @@ typedef struct xfs_dir2_block_tail {
__be32 stale; /* count of stale lf entries */
} xfs_dir2_block_tail_t;
/*
* Pointer to the leaf header embedded in a data block (1-block format)
*/
static inline struct xfs_dir2_block_tail *
xfs_dir2_block_tail_p(struct xfs_mount *mp, struct xfs_dir2_data_hdr *hdr)
{
return ((struct xfs_dir2_block_tail *)
((char *)hdr + mp->m_dirblksize)) - 1;
}
/*
* Pointer to the leaf entries embedded in a data block (1-block format)
*/
@ -764,10 +614,6 @@ xfs_dir2_block_leaf_p(struct xfs_dir2_block_tail *btp)
* of an attribute name may not be unique, we may have duplicate keys. The
* internal links in the Btree are logical block offsets into the file.
*
*========================================================================
* Attribute structure when equal to XFS_LBSIZE(mp) bytes.
*========================================================================
*
* Struct leaf_entry's are packed from the top. Name/values grow from the
* bottom but are not packed. The freemap contains run-length-encoded entries
* for the free bytes after the leaf_entry's, but only the N largest such,

View file

@ -85,38 +85,74 @@ static struct xfs_nameops xfs_ascii_ci_nameops = {
.compname = xfs_ascii_ci_compname,
};
void
xfs_dir_mount(
xfs_mount_t *mp)
int
xfs_da_mount(
struct xfs_mount *mp)
{
int nodehdr_size;
struct xfs_da_geometry *dageo;
int nodehdr_size;
ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT);
ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
XFS_MAX_BLOCKSIZE);
mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL);
mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL);
mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
nodehdr_size = mp->m_dir_inode_ops->node_hdr_size;
mp->m_attr_node_ents = (mp->m_sb.sb_blocksize - nodehdr_size) /
(uint)sizeof(xfs_da_node_entry_t);
mp->m_dir_node_ents = (mp->m_dirblksize - nodehdr_size) /
(uint)sizeof(xfs_da_node_entry_t);
mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
KM_SLEEP | KM_MAYFAIL);
mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry),
KM_SLEEP | KM_MAYFAIL);
if (!mp->m_dir_geo || !mp->m_attr_geo) {
kmem_free(mp->m_dir_geo);
kmem_free(mp->m_attr_geo);
return ENOMEM;
}
/* set up directory geometry */
dageo = mp->m_dir_geo;
dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog;
dageo->fsblog = mp->m_sb.sb_blocklog;
dageo->blksize = 1 << dageo->blklog;
dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog;
/*
* Now we've set up the block conversion variables, we can calculate the
* segment block constants using the geometry structure.
*/
dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET);
dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET);
dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET);
dageo->node_ents = (dageo->blksize - nodehdr_size) /
(uint)sizeof(xfs_da_node_entry_t);
dageo->magicpct = (dageo->blksize * 37) / 100;
/* set up attribute geometry - single fsb only */
dageo = mp->m_attr_geo;
dageo->blklog = mp->m_sb.sb_blocklog;
dageo->fsblog = mp->m_sb.sb_blocklog;
dageo->blksize = 1 << dageo->blklog;
dageo->fsbcount = 1;
dageo->node_ents = (dageo->blksize - nodehdr_size) /
(uint)sizeof(xfs_da_node_entry_t);
dageo->magicpct = (dageo->blksize * 37) / 100;
mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
if (xfs_sb_version_hasasciici(&mp->m_sb))
mp->m_dirnameops = &xfs_ascii_ci_nameops;
else
mp->m_dirnameops = &xfs_default_nameops;
return 0;
}
void
xfs_da_unmount(
struct xfs_mount *mp)
{
kmem_free(mp->m_dir_geo);
kmem_free(mp->m_attr_geo);
}
/*
@ -192,6 +228,7 @@ xfs_dir_init(
if (!args)
return ENOMEM;
args->geo = dp->i_mount->m_dir_geo;
args->dp = dp;
args->trans = tp;
error = xfs_dir2_sf_create(args, pdp->i_ino);
@ -226,6 +263,7 @@ xfs_dir_createname(
if (!args)
return ENOMEM;
args->geo = dp->i_mount->m_dir_geo;
args->name = name->name;
args->namelen = name->len;
args->filetype = name->type;
@ -244,7 +282,7 @@ xfs_dir_createname(
goto out_free;
}
rval = xfs_dir2_isblock(tp, dp, &v);
rval = xfs_dir2_isblock(args, &v);
if (rval)
goto out_free;
if (v) {
@ -252,7 +290,7 @@ xfs_dir_createname(
goto out_free;
}
rval = xfs_dir2_isleaf(tp, dp, &v);
rval = xfs_dir2_isleaf(args, &v);
if (rval)
goto out_free;
if (v)
@ -320,6 +358,7 @@ xfs_dir_lookup(
* annotations into the reclaim path for the ilock.
*/
args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
args->geo = dp->i_mount->m_dir_geo;
args->name = name->name;
args->namelen = name->len;
args->filetype = name->type;
@ -336,7 +375,7 @@ xfs_dir_lookup(
goto out_check_rval;
}
rval = xfs_dir2_isblock(tp, dp, &v);
rval = xfs_dir2_isblock(args, &v);
if (rval)
goto out_free;
if (v) {
@ -344,7 +383,7 @@ xfs_dir_lookup(
goto out_check_rval;
}
rval = xfs_dir2_isleaf(tp, dp, &v);
rval = xfs_dir2_isleaf(args, &v);
if (rval)
goto out_free;
if (v)
@ -391,6 +430,7 @@ xfs_dir_removename(
if (!args)
return ENOMEM;
args->geo = dp->i_mount->m_dir_geo;
args->name = name->name;
args->namelen = name->len;
args->filetype = name->type;
@ -408,7 +448,7 @@ xfs_dir_removename(
goto out_free;
}
rval = xfs_dir2_isblock(tp, dp, &v);
rval = xfs_dir2_isblock(args, &v);
if (rval)
goto out_free;
if (v) {
@ -416,7 +456,7 @@ xfs_dir_removename(
goto out_free;
}
rval = xfs_dir2_isleaf(tp, dp, &v);
rval = xfs_dir2_isleaf(args, &v);
if (rval)
goto out_free;
if (v)
@ -455,6 +495,7 @@ xfs_dir_replace(
if (!args)
return ENOMEM;
args->geo = dp->i_mount->m_dir_geo;
args->name = name->name;
args->namelen = name->len;
args->filetype = name->type;
@ -472,7 +513,7 @@ xfs_dir_replace(
goto out_free;
}
rval = xfs_dir2_isblock(tp, dp, &v);
rval = xfs_dir2_isblock(args, &v);
if (rval)
goto out_free;
if (v) {
@ -480,7 +521,7 @@ xfs_dir_replace(
goto out_free;
}
rval = xfs_dir2_isleaf(tp, dp, &v);
rval = xfs_dir2_isleaf(args, &v);
if (rval)
goto out_free;
if (v)
@ -516,6 +557,7 @@ xfs_dir_canenter(
if (!args)
return ENOMEM;
args->geo = dp->i_mount->m_dir_geo;
args->name = name->name;
args->namelen = name->len;
args->filetype = name->type;
@ -531,7 +573,7 @@ xfs_dir_canenter(
goto out_free;
}
rval = xfs_dir2_isblock(tp, dp, &v);
rval = xfs_dir2_isblock(args, &v);
if (rval)
goto out_free;
if (v) {
@ -539,7 +581,7 @@ xfs_dir_canenter(
goto out_free;
}
rval = xfs_dir2_isleaf(tp, dp, &v);
rval = xfs_dir2_isleaf(args, &v);
if (rval)
goto out_free;
if (v)
@ -579,13 +621,13 @@ xfs_dir2_grow_inode(
* Set lowest possible block in the space requested.
*/
bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
count = mp->m_dirblkfsbs;
count = args->geo->fsbcount;
error = xfs_da_grow_inode_int(args, &bno, count);
if (error)
return error;
*dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
*dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno);
/*
* Update file's size if this is the data space and it grew.
@ -607,19 +649,16 @@ xfs_dir2_grow_inode(
*/
int
xfs_dir2_isblock(
xfs_trans_t *tp,
xfs_inode_t *dp,
int *vp) /* out: 1 is block, 0 is not block */
struct xfs_da_args *args,
int *vp) /* out: 1 is block, 0 is not block */
{
xfs_fileoff_t last; /* last file offset */
xfs_mount_t *mp;
int rval;
xfs_fileoff_t last; /* last file offset */
int rval;
mp = dp->i_mount;
if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
return rval;
rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize);
*vp = rval;
return 0;
}
@ -629,18 +668,15 @@ xfs_dir2_isblock(
*/
int
xfs_dir2_isleaf(
xfs_trans_t *tp,
xfs_inode_t *dp,
int *vp) /* out: 1 is leaf, 0 is not leaf */
struct xfs_da_args *args,
int *vp) /* out: 1 is block, 0 is not block */
{
xfs_fileoff_t last; /* last file offset */
xfs_mount_t *mp;
int rval;
xfs_fileoff_t last; /* last file offset */
int rval;
mp = dp->i_mount;
if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
return rval;
*vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
*vp = last == args->geo->leafblk + args->geo->fsbcount;
return 0;
}
@ -668,11 +704,11 @@ xfs_dir2_shrink_inode(
dp = args->dp;
mp = dp->i_mount;
tp = args->trans;
da = xfs_dir2_db_to_da(mp, db);
da = xfs_dir2_db_to_da(args->geo, db);
/*
* Unmap the fsblock(s).
*/
if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
if ((error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount,
XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
&done))) {
/*
@ -699,12 +735,12 @@ xfs_dir2_shrink_inode(
/*
* If it's not a data block, we're done.
*/
if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET))
return 0;
/*
* If the block isn't the last one in the directory, we're done.
*/
if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0))
if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0))
return 0;
bno = da;
if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
@ -713,7 +749,7 @@ xfs_dir2_shrink_inode(
*/
return error;
}
if (db == mp->m_dirdatablk)
if (db == args->geo->datablk)
ASSERT(bno == 0);
else
ASSERT(bno > 0);

View file

@ -80,7 +80,7 @@ struct xfs_dir_ops {
struct xfs_dir3_icleaf_hdr *from);
void (*leaf_hdr_from_disk)(struct xfs_dir3_icleaf_hdr *to,
struct xfs_dir2_leaf *from);
int (*leaf_max_ents)(struct xfs_mount *mp);
int (*leaf_max_ents)(struct xfs_da_geometry *geo);
struct xfs_dir2_leaf_entry *
(*leaf_ents_p)(struct xfs_dir2_leaf *lp);
@ -97,10 +97,12 @@ struct xfs_dir_ops {
struct xfs_dir3_icfree_hdr *from);
void (*free_hdr_from_disk)(struct xfs_dir3_icfree_hdr *to,
struct xfs_dir2_free *from);
int (*free_max_bests)(struct xfs_mount *mp);
int (*free_max_bests)(struct xfs_da_geometry *geo);
__be16 * (*free_bests_p)(struct xfs_dir2_free *free);
xfs_dir2_db_t (*db_to_fdb)(struct xfs_mount *mp, xfs_dir2_db_t db);
int (*db_to_fdindex)(struct xfs_mount *mp, xfs_dir2_db_t db);
xfs_dir2_db_t (*db_to_fdb)(struct xfs_da_geometry *geo,
xfs_dir2_db_t db);
int (*db_to_fdindex)(struct xfs_da_geometry *geo,
xfs_dir2_db_t db);
};
extern const struct xfs_dir_ops *
@ -112,7 +114,9 @@ extern const struct xfs_dir_ops *
* Generic directory interface routines
*/
extern void xfs_dir_startup(void);
extern void xfs_dir_mount(struct xfs_mount *mp);
extern int xfs_da_mount(struct xfs_mount *mp);
extern void xfs_da_unmount(struct xfs_mount *mp);
extern int xfs_dir_isempty(struct xfs_inode *dp);
extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp,
struct xfs_inode *pdp);
@ -142,23 +146,23 @@ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
/*
* Interface routines used by userspace utilities
*/
extern int xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
extern int xfs_dir2_isblock(struct xfs_da_args *args, int *r);
extern int xfs_dir2_isleaf(struct xfs_da_args *args, int *r);
extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
struct xfs_buf *bp);
extern void xfs_dir2_data_freescan(struct xfs_inode *dp,
struct xfs_dir2_data_hdr *hdr, int *loghead);
extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_inode *dp,
extern void xfs_dir2_data_log_entry(struct xfs_da_args *args,
struct xfs_buf *bp, struct xfs_dir2_data_entry *dep);
extern void xfs_dir2_data_log_header(struct xfs_trans *tp, struct xfs_inode *dp,
extern void xfs_dir2_data_log_header(struct xfs_da_args *args,
struct xfs_buf *bp);
extern void xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_buf *bp,
struct xfs_dir2_data_unused *dup);
extern void xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_inode *dp,
extern void xfs_dir2_data_log_unused(struct xfs_da_args *args,
struct xfs_buf *bp, struct xfs_dir2_data_unused *dup);
extern void xfs_dir2_data_make_free(struct xfs_da_args *args,
struct xfs_buf *bp, xfs_dir2_data_aoff_t offset,
xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_inode *dp,
extern void xfs_dir2_data_use_free(struct xfs_da_args *args,
struct xfs_buf *bp, struct xfs_dir2_data_unused *dup,
xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
int *needlogp, int *needscanp);

View file

@ -136,7 +136,7 @@ xfs_dir3_block_read(
struct xfs_mount *mp = dp->i_mount;
int err;
err = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, bpp,
err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
if (!err && tp)
xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
@ -281,8 +281,7 @@ xfs_dir2_block_need_space(
*/
static void
xfs_dir2_block_compact(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp,
struct xfs_dir2_data_hdr *hdr,
struct xfs_dir2_block_tail *btp,
@ -315,18 +314,17 @@ xfs_dir2_block_compact(
*lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1);
*lfloghigh -= be32_to_cpu(btp->stale) - 1;
be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1));
xfs_dir2_data_make_free(tp, dp, bp,
xfs_dir2_data_make_free(args, bp,
(xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr),
(xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)),
needlog, &needscan);
blp += be32_to_cpu(btp->stale) - 1;
btp->stale = cpu_to_be32(1);
/*
* If we now need to rebuild the bestfree map, do so.
* This needs to happen before the next call to use_free.
*/
if (needscan)
xfs_dir2_data_freescan(dp, hdr, needlog);
xfs_dir2_data_freescan(args->dp, hdr, needlog);
}
/*
@ -378,7 +376,7 @@ xfs_dir2_block_addname(
* Set up pointers to parts of the block.
*/
hdr = bp->b_addr;
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
@ -421,7 +419,7 @@ xfs_dir2_block_addname(
* If need to compact the leaf entries, do it now.
*/
if (compact) {
xfs_dir2_block_compact(tp, dp, bp, hdr, btp, blp, &needlog,
xfs_dir2_block_compact(args, bp, hdr, btp, blp, &needlog,
&lfloghigh, &lfloglow);
/* recalculate blp post-compaction */
blp = xfs_dir2_block_leaf_p(btp);
@ -456,7 +454,7 @@ xfs_dir2_block_addname(
/*
* Mark the space needed for the new leaf entry, now in use.
*/
xfs_dir2_data_use_free(tp, dp, bp, enddup,
xfs_dir2_data_use_free(args, bp, enddup,
(xfs_dir2_data_aoff_t)
((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) -
sizeof(*blp)),
@ -537,13 +535,13 @@ xfs_dir2_block_addname(
* Fill in the leaf entry.
*/
blp[mid].hashval = cpu_to_be32(args->hashval);
blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
(char *)dep - (char *)hdr));
xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
/*
* Mark space for the data entry used.
*/
xfs_dir2_data_use_free(tp, dp, bp, dup,
xfs_dir2_data_use_free(args, bp, dup,
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
(xfs_dir2_data_aoff_t)len, &needlog, &needscan);
/*
@ -561,9 +559,9 @@ xfs_dir2_block_addname(
if (needscan)
xfs_dir2_data_freescan(dp, hdr, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dp, bp);
xfs_dir2_data_log_header(args, bp);
xfs_dir2_block_log_tail(tp, bp);
xfs_dir2_data_log_entry(tp, dp, bp, dep);
xfs_dir2_data_log_entry(args, bp, dep);
xfs_dir3_data_check(dp, bp);
return 0;
}
@ -582,7 +580,7 @@ xfs_dir2_block_log_leaf(
xfs_dir2_leaf_entry_t *blp;
xfs_dir2_block_tail_t *btp;
btp = xfs_dir2_block_tail_p(tp->t_mountp, hdr);
btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
xfs_trans_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr),
(uint)((char *)&blp[last + 1] - (char *)hdr - 1));
@ -599,7 +597,7 @@ xfs_dir2_block_log_tail(
xfs_dir2_data_hdr_t *hdr = bp->b_addr;
xfs_dir2_block_tail_t *btp;
btp = xfs_dir2_block_tail_p(tp->t_mountp, hdr);
btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr);
xfs_trans_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr),
(uint)((char *)(btp + 1) - (char *)hdr - 1));
}
@ -634,13 +632,14 @@ xfs_dir2_block_lookup(
mp = dp->i_mount;
hdr = bp->b_addr;
xfs_dir3_data_check(dp, bp);
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
* Get the offset from the leaf entry, to point to the data.
*/
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
xfs_dir2_dataptr_to_off(args->geo,
be32_to_cpu(blp[ent].address)));
/*
* Fill in inode number, CI name if appropriate, release the block.
*/
@ -686,7 +685,7 @@ xfs_dir2_block_lookup_int(
hdr = bp->b_addr;
xfs_dir3_data_check(dp, bp);
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
* Loop doing a binary search for our hash value.
@ -724,7 +723,7 @@ xfs_dir2_block_lookup_int(
* Get pointer to the entry from the leaf.
*/
dep = (xfs_dir2_data_entry_t *)
((char *)hdr + xfs_dir2_dataptr_to_off(mp, addr));
((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, addr));
/*
* Compare name and if it's an exact match, return the index
* and buffer. If it's the first case-insensitive match, store
@ -791,18 +790,19 @@ xfs_dir2_block_removename(
tp = args->trans;
mp = dp->i_mount;
hdr = bp->b_addr;
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
* Point to the data entry using the leaf entry.
*/
dep = (xfs_dir2_data_entry_t *)
((char *)hdr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
xfs_dir2_dataptr_to_off(args->geo,
be32_to_cpu(blp[ent].address)));
/*
* Mark the data entry's space free.
*/
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, dp, bp,
xfs_dir2_data_make_free(args, bp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
/*
@ -821,7 +821,7 @@ xfs_dir2_block_removename(
if (needscan)
xfs_dir2_data_freescan(dp, hdr, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dp, bp);
xfs_dir2_data_log_header(args, bp);
xfs_dir3_data_check(dp, bp);
/*
* See if the size as a shortform is good enough.
@ -866,20 +866,21 @@ xfs_dir2_block_replace(
dp = args->dp;
mp = dp->i_mount;
hdr = bp->b_addr;
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
* Point to the data entry we need to change.
*/
dep = (xfs_dir2_data_entry_t *)
((char *)hdr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
xfs_dir2_dataptr_to_off(args->geo,
be32_to_cpu(blp[ent].address)));
ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
/*
* Change the inode number to the new value.
*/
dep->inumber = cpu_to_be64(args->inumber);
dp->d_ops->data_put_ftype(dep, args->filetype);
xfs_dir2_data_log_entry(args->trans, dp, bp, dep);
xfs_dir2_data_log_entry(args, bp, dep);
xfs_dir3_data_check(dp, bp);
return 0;
}
@ -939,7 +940,7 @@ xfs_dir2_leaf_to_block(
leaf = lbp->b_addr;
dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
ents = dp->d_ops->leaf_ents_p(leaf);
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC ||
leafhdr.magic == XFS_DIR3_LEAF1_MAGIC);
@ -949,13 +950,13 @@ xfs_dir2_leaf_to_block(
* been left behind during no-space-reservation operations.
* These will show up in the leaf bests table.
*/
while (dp->i_d.di_size > mp->m_dirblksize) {
while (dp->i_d.di_size > args->geo->blksize) {
int hdrsz;
hdrsz = dp->d_ops->data_entry_offset;
bestsp = xfs_dir2_leaf_bests_p(ltp);
if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
mp->m_dirblksize - hdrsz) {
args->geo->blksize - hdrsz) {
if ((error =
xfs_dir2_leaf_trim_data(args, lbp,
(xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1))))
@ -967,7 +968,7 @@ xfs_dir2_leaf_to_block(
* Read the data block if we don't already have it, give up if it fails.
*/
if (!dbp) {
error = xfs_dir3_data_read(tp, dp, mp->m_dirdatablk, -1, &dbp);
error = xfs_dir3_data_read(tp, dp, args->geo->datablk, -1, &dbp);
if (error)
return error;
}
@ -983,7 +984,7 @@ xfs_dir2_leaf_to_block(
/*
* Look at the last data entry.
*/
tagp = (__be16 *)((char *)hdr + mp->m_dirblksize) - 1;
tagp = (__be16 *)((char *)hdr + args->geo->blksize) - 1;
dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
/*
* If it's not free or is too short we can't do it.
@ -1002,12 +1003,12 @@ xfs_dir2_leaf_to_block(
/*
* Use up the space at the end of the block (blp/btp).
*/
xfs_dir2_data_use_free(tp, dp, dbp, dup, mp->m_dirblksize - size, size,
xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size,
&needlog, &needscan);
/*
* Initialize the block tail.
*/
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
btp->count = cpu_to_be32(leafhdr.count - leafhdr.stale);
btp->stale = 0;
xfs_dir2_block_log_tail(tp, dbp);
@ -1028,11 +1029,11 @@ xfs_dir2_leaf_to_block(
if (needscan)
xfs_dir2_data_freescan(dp, hdr, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dp, dbp);
xfs_dir2_data_log_header(args, dbp);
/*
* Pitch the old leaf block.
*/
error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp);
error = xfs_da_shrink_inode(args, args->geo->leafblk, lbp);
if (error)
return error;
@ -1141,13 +1142,13 @@ xfs_dir2_sf_to_block(
*/
dup = dp->d_ops->data_unused_p(hdr);
needlog = needscan = 0;
xfs_dir2_data_use_free(tp, dp, bp, dup, mp->m_dirblksize - i, i, &needlog,
&needscan);
xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i,
i, &needlog, &needscan);
ASSERT(needscan == 0);
/*
* Fill in the tail.
*/
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
btp->count = cpu_to_be32(sfp->count + 2); /* ., .. */
btp->stale = 0;
blp = xfs_dir2_block_leaf_p(btp);
@ -1155,7 +1156,7 @@ xfs_dir2_sf_to_block(
/*
* Remove the freespace, we'll manage it.
*/
xfs_dir2_data_use_free(tp, dp, bp, dup,
xfs_dir2_data_use_free(args, bp, dup,
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr),
be16_to_cpu(dup->length), &needlog, &needscan);
/*
@ -1168,9 +1169,9 @@ xfs_dir2_sf_to_block(
dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, dp, bp, dep);
xfs_dir2_data_log_entry(args, bp, dep);
blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
(char *)dep - (char *)hdr));
/*
* Create entry for ..
@ -1182,9 +1183,9 @@ xfs_dir2_sf_to_block(
dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, dp, bp, dep);
xfs_dir2_data_log_entry(args, bp, dep);
blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
(char *)dep - (char *)hdr));
offset = dp->d_ops->data_first_offset;
/*
@ -1216,7 +1217,7 @@ xfs_dir2_sf_to_block(
dup->length = cpu_to_be16(newoffset - offset);
*xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(
((char *)dup - (char *)hdr));
xfs_dir2_data_log_unused(tp, bp, dup);
xfs_dir2_data_log_unused(args, bp, dup);
xfs_dir2_data_freeinsert(hdr,
dp->d_ops->data_bestfree_p(hdr),
dup, &dummy);
@ -1233,12 +1234,12 @@ xfs_dir2_sf_to_block(
memcpy(dep->name, sfep->name, dep->namelen);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, dp, bp, dep);
xfs_dir2_data_log_entry(args, bp, dep);
name.name = sfep->name;
name.len = sfep->namelen;
blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->
hashname(&name));
blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(
(char *)dep - (char *)hdr));
offset = (int)((char *)(tagp + 1) - (char *)hdr);
if (++i == sfp->count)

View file

@ -63,8 +63,10 @@ __xfs_dir3_data_check(
int stale; /* count of stale leaves */
struct xfs_name name;
const struct xfs_dir_ops *ops;
struct xfs_da_geometry *geo;
mp = bp->b_target->bt_mount;
geo = mp->m_dir_geo;
/*
* We can be passed a null dp here from a verifier, so we need to go the
@ -78,7 +80,7 @@ __xfs_dir3_data_check(
switch (hdr->magic) {
case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(geo, hdr);
lep = xfs_dir2_block_leaf_p(btp);
endp = (char *)lep;
@ -94,7 +96,7 @@ __xfs_dir3_data_check(
break;
case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
endp = (char *)hdr + mp->m_dirblksize;
endp = (char *)hdr + geo->blksize;
break;
default:
XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp);
@ -172,9 +174,9 @@ __xfs_dir3_data_check(
lastfree = 0;
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)hdr));
addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)hdr));
name.name = dep->name;
name.len = dep->namelen;
hash = mp->m_dirnameops->hashname(&name);
@ -329,12 +331,11 @@ xfs_dir3_data_read(
int
xfs_dir3_data_readahead(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_dablk_t bno,
xfs_daddr_t mapped_bno)
{
return xfs_da_reada_buf(tp, dp, bno, mapped_bno,
return xfs_da_reada_buf(dp, bno, mapped_bno,
XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops);
}
@ -510,6 +511,7 @@ xfs_dir2_data_freescan(
struct xfs_dir2_data_free *bf;
char *endp; /* end of block's data */
char *p; /* current entry pointer */
struct xfs_da_geometry *geo = dp->i_mount->m_dir_geo;
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
@ -528,10 +530,10 @@ xfs_dir2_data_freescan(
p = (char *)dp->d_ops->data_entry_p(hdr);
if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
btp = xfs_dir2_block_tail_p(dp->i_mount, hdr);
btp = xfs_dir2_block_tail_p(geo, hdr);
endp = (char *)xfs_dir2_block_leaf_p(btp);
} else
endp = (char *)hdr + dp->i_mount->m_dirblksize;
endp = (char *)hdr + geo->blksize;
/*
* Loop over the block's entries.
*/
@ -585,8 +587,8 @@ xfs_dir3_data_init(
/*
* Get the buffer set up for the block.
*/
error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
XFS_DATA_FORK);
error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
-1, &bp, XFS_DATA_FORK);
if (error)
return error;
bp->b_ops = &xfs_dir3_data_buf_ops;
@ -621,15 +623,15 @@ xfs_dir3_data_init(
dup = dp->d_ops->data_unused_p(hdr);
dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
t = mp->m_dirblksize - (uint)dp->d_ops->data_entry_offset;
t = args->geo->blksize - (uint)dp->d_ops->data_entry_offset;
bf[0].length = cpu_to_be16(t);
dup->length = cpu_to_be16(t);
*xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
/*
* Log it and return it.
*/
xfs_dir2_data_log_header(tp, dp, bp);
xfs_dir2_data_log_unused(tp, bp, dup);
xfs_dir2_data_log_header(args, bp);
xfs_dir2_data_log_unused(args, bp, dup);
*bpp = bp;
return 0;
}
@ -639,8 +641,7 @@ xfs_dir3_data_init(
*/
void
xfs_dir2_data_log_entry(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp,
xfs_dir2_data_entry_t *dep) /* data entry pointer */
{
@ -651,8 +652,8 @@ xfs_dir2_data_log_entry(
hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
(uint)((char *)(dp->d_ops->data_entry_tag_p(dep) + 1) -
xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr),
(uint)((char *)(args->dp->d_ops->data_entry_tag_p(dep) + 1) -
(char *)hdr - 1));
}
@ -661,8 +662,7 @@ xfs_dir2_data_log_entry(
*/
void
xfs_dir2_data_log_header(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp)
{
#ifdef DEBUG
@ -674,7 +674,8 @@ xfs_dir2_data_log_header(
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
#endif
xfs_trans_log_buf(tp, bp, 0, dp->d_ops->data_entry_offset - 1);
xfs_trans_log_buf(args->trans, bp, 0,
args->dp->d_ops->data_entry_offset - 1);
}
/*
@ -682,7 +683,7 @@ xfs_dir2_data_log_header(
*/
void
xfs_dir2_data_log_unused(
struct xfs_trans *tp,
struct xfs_da_args *args,
struct xfs_buf *bp,
xfs_dir2_data_unused_t *dup) /* data unused pointer */
{
@ -696,13 +697,13 @@ xfs_dir2_data_log_unused(
/*
* Log the first part of the unused entry.
*/
xfs_trans_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr),
(uint)((char *)&dup->length + sizeof(dup->length) -
1 - (char *)hdr));
/*
* Log the end (tag) of the unused entry.
*/
xfs_trans_log_buf(tp, bp,
xfs_trans_log_buf(args->trans, bp,
(uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
(uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
sizeof(xfs_dir2_data_off_t) - 1));
@ -714,8 +715,7 @@ xfs_dir2_data_log_unused(
*/
void
xfs_dir2_data_make_free(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp,
xfs_dir2_data_aoff_t offset, /* starting byte offset */
xfs_dir2_data_aoff_t len, /* length in bytes */
@ -725,14 +725,12 @@ xfs_dir2_data_make_free(
xfs_dir2_data_hdr_t *hdr; /* data block pointer */
xfs_dir2_data_free_t *dfp; /* bestfree pointer */
char *endptr; /* end of data area */
xfs_mount_t *mp; /* filesystem mount point */
int needscan; /* need to regen bestfree */
xfs_dir2_data_unused_t *newdup; /* new unused entry */
xfs_dir2_data_unused_t *postdup; /* unused entry after us */
xfs_dir2_data_unused_t *prevdup; /* unused entry before us */
struct xfs_dir2_data_free *bf;
mp = tp->t_mountp;
hdr = bp->b_addr;
/*
@ -740,20 +738,20 @@ xfs_dir2_data_make_free(
*/
if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC))
endptr = (char *)hdr + mp->m_dirblksize;
endptr = (char *)hdr + args->geo->blksize;
else {
xfs_dir2_block_tail_t *btp; /* block tail */
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
endptr = (char *)xfs_dir2_block_leaf_p(btp);
}
/*
* If this isn't the start of the block, then back up to
* the previous entry and see if it's free.
*/
if (offset > dp->d_ops->data_entry_offset) {
if (offset > args->dp->d_ops->data_entry_offset) {
__be16 *tagp; /* tag just before us */
tagp = (__be16 *)((char *)hdr + offset) - 1;
@ -779,7 +777,7 @@ xfs_dir2_data_make_free(
* Previous and following entries are both free,
* merge everything into a single free entry.
*/
bf = dp->d_ops->data_bestfree_p(hdr);
bf = args->dp->d_ops->data_bestfree_p(hdr);
if (prevdup && postdup) {
xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */
@ -801,7 +799,7 @@ xfs_dir2_data_make_free(
be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length));
*xfs_dir2_data_unused_tag_p(prevdup) =
cpu_to_be16((char *)prevdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, prevdup);
xfs_dir2_data_log_unused(args, bp, prevdup);
if (!needscan) {
/*
* Has to be the case that entries 0 and 1 are
@ -836,7 +834,7 @@ xfs_dir2_data_make_free(
be16_add_cpu(&prevdup->length, len);
*xfs_dir2_data_unused_tag_p(prevdup) =
cpu_to_be16((char *)prevdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, prevdup);
xfs_dir2_data_log_unused(args, bp, prevdup);
/*
* If the previous entry was in the table, the new entry
* is longer, so it will be in the table too. Remove
@ -864,7 +862,7 @@ xfs_dir2_data_make_free(
newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
*xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, newdup);
xfs_dir2_data_log_unused(args, bp, newdup);
/*
* If the following entry was in the table, the new entry
* is longer, so it will be in the table too. Remove
@ -891,7 +889,7 @@ xfs_dir2_data_make_free(
newdup->length = cpu_to_be16(len);
*xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, newdup);
xfs_dir2_data_log_unused(args, bp, newdup);
xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
}
*needscanp = needscan;
@ -902,8 +900,7 @@ xfs_dir2_data_make_free(
*/
void
xfs_dir2_data_use_free(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp,
xfs_dir2_data_unused_t *dup, /* unused entry */
xfs_dir2_data_aoff_t offset, /* starting offset to use */
@ -934,7 +931,7 @@ xfs_dir2_data_use_free(
* Look up the entry in the bestfree table.
*/
oldlen = be16_to_cpu(dup->length);
bf = dp->d_ops->data_bestfree_p(hdr);
bf = args->dp->d_ops->data_bestfree_p(hdr);
dfp = xfs_dir2_data_freefind(hdr, bf, dup);
ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
/*
@ -966,7 +963,7 @@ xfs_dir2_data_use_free(
newdup->length = cpu_to_be16(oldlen - len);
*xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, newdup);
xfs_dir2_data_log_unused(args, bp, newdup);
/*
* If it was in the table, remove it and add the new one.
*/
@ -994,7 +991,7 @@ xfs_dir2_data_use_free(
newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
*xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, newdup);
xfs_dir2_data_log_unused(args, bp, newdup);
/*
* If it was in the table, remove it and add the new one.
*/
@ -1022,13 +1019,13 @@ xfs_dir2_data_use_free(
newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
*xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, newdup);
xfs_dir2_data_log_unused(args, bp, newdup);
newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
*xfs_dir2_data_unused_tag_p(newdup2) =
cpu_to_be16((char *)newdup2 - (char *)hdr);
xfs_dir2_data_log_unused(tp, bp, newdup2);
xfs_dir2_data_log_unused(args, bp, newdup2);
/*
* If the old entry was in the table, we need to scan
* if the 3rd entry was valid, since these entries

View file

@ -41,9 +41,10 @@
*/
static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp,
int *indexp, struct xfs_buf **dbpp);
static void xfs_dir3_leaf_log_bests(struct xfs_trans *tp, struct xfs_buf *bp,
int first, int last);
static void xfs_dir3_leaf_log_tail(struct xfs_trans *tp, struct xfs_buf *bp);
static void xfs_dir3_leaf_log_bests(struct xfs_da_args *args,
struct xfs_buf *bp, int first, int last);
static void xfs_dir3_leaf_log_tail(struct xfs_da_args *args,
struct xfs_buf *bp);
/*
* Check the internal consistency of a leaf1 block.
@ -92,6 +93,7 @@ xfs_dir3_leaf_check_int(
int i;
const struct xfs_dir_ops *ops;
struct xfs_dir3_icleaf_hdr leafhdr;
struct xfs_da_geometry *geo = mp->m_dir_geo;
/*
* we can be passed a null dp here from a verifier, so we need to go the
@ -105,14 +107,14 @@ xfs_dir3_leaf_check_int(
}
ents = ops->leaf_ents_p(leaf);
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(geo, leaf);
/*
* XXX (dgc): This value is not restrictive enough.
* Should factor in the size of the bests table as well.
* We can deduce a value for that from di_size.
*/
if (hdr->count > ops->leaf_max_ents(mp))
if (hdr->count > ops->leaf_max_ents(geo))
return false;
/* Leaves and bests don't overlap in leaf format. */
@ -323,7 +325,7 @@ xfs_dir3_leaf_init(
if (type == XFS_DIR2_LEAF1_MAGIC) {
struct xfs_dir2_leaf_tail *ltp;
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
ltp->bestcount = 0;
bp->b_ops = &xfs_dir3_leaf1_buf_ops;
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAF1_BUF);
@ -347,18 +349,18 @@ xfs_dir3_leaf_get_buf(
int error;
ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC);
ASSERT(bno >= XFS_DIR2_LEAF_FIRSTDB(mp) &&
bno < XFS_DIR2_FREE_FIRSTDB(mp));
ASSERT(bno >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET) &&
bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, bno), -1, &bp,
XFS_DATA_FORK);
error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
-1, &bp, XFS_DATA_FORK);
if (error)
return error;
xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic);
xfs_dir3_leaf_log_header(tp, dp, bp);
xfs_dir3_leaf_log_header(args, bp);
if (magic == XFS_DIR2_LEAF1_MAGIC)
xfs_dir3_leaf_log_tail(tp, bp);
xfs_dir3_leaf_log_tail(args, bp);
*bpp = bp;
return 0;
}
@ -403,8 +405,8 @@ xfs_dir2_block_to_leaf(
if ((error = xfs_da_grow_inode(args, &blkno))) {
return error;
}
ldb = xfs_dir2_da_to_db(mp, blkno);
ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp));
ldb = xfs_dir2_da_to_db(args->geo, blkno);
ASSERT(ldb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET));
/*
* Initialize the leaf block, get a buffer for it.
*/
@ -415,7 +417,7 @@ xfs_dir2_block_to_leaf(
leaf = lbp->b_addr;
hdr = dbp->b_addr;
xfs_dir3_data_check(dp, dbp);
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
bf = dp->d_ops->data_bestfree_p(hdr);
ents = dp->d_ops->leaf_ents_p(leaf);
@ -427,23 +429,23 @@ xfs_dir2_block_to_leaf(
leafhdr.count = be32_to_cpu(btp->count);
leafhdr.stale = be32_to_cpu(btp->stale);
dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
xfs_dir3_leaf_log_header(tp, dp, lbp);
xfs_dir3_leaf_log_header(args, lbp);
/*
* Could compact these but I think we always do the conversion
* after squeezing out stale entries.
*/
memcpy(ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir3_leaf_log_ents(tp, dp, lbp, 0, leafhdr.count - 1);
xfs_dir3_leaf_log_ents(args, lbp, 0, leafhdr.count - 1);
needscan = 0;
needlog = 1;
/*
* Make the space formerly occupied by the leaf entries and block
* tail be free.
*/
xfs_dir2_data_make_free(tp, dp, dbp,
xfs_dir2_data_make_free(args, dbp,
(xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr),
(xfs_dir2_data_aoff_t)((char *)hdr + mp->m_dirblksize -
(xfs_dir2_data_aoff_t)((char *)hdr + args->geo->blksize -
(char *)blp),
&needlog, &needscan);
/*
@ -461,7 +463,7 @@ xfs_dir2_block_to_leaf(
/*
* Set up leaf tail and bests table.
*/
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
ltp->bestcount = cpu_to_be32(1);
bestsp = xfs_dir2_leaf_bests_p(ltp);
bestsp[0] = bf[0].length;
@ -469,10 +471,10 @@ xfs_dir2_block_to_leaf(
* Log the data header and leaf bests table.
*/
if (needlog)
xfs_dir2_data_log_header(tp, dp, dbp);
xfs_dir2_data_log_header(args, dbp);
xfs_dir3_leaf_check(dp, lbp);
xfs_dir3_data_check(dp, dbp);
xfs_dir3_leaf_log_bests(tp, lbp, 0, 0);
xfs_dir3_leaf_log_bests(args, lbp, 0, 0);
return 0;
}
@ -641,7 +643,7 @@ xfs_dir2_leaf_addname(
tp = args->trans;
mp = dp->i_mount;
error = xfs_dir3_leaf_read(tp, dp, mp->m_dirleafblk, -1, &lbp);
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
if (error)
return error;
@ -653,7 +655,7 @@ xfs_dir2_leaf_addname(
*/
index = xfs_dir2_leaf_search_hash(args, lbp);
leaf = lbp->b_addr;
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
ents = dp->d_ops->leaf_ents_p(leaf);
dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
bestsp = xfs_dir2_leaf_bests_p(ltp);
@ -670,7 +672,7 @@ xfs_dir2_leaf_addname(
index++, lep++) {
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
continue;
i = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
i = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
ASSERT(i < be32_to_cpu(ltp->bestcount));
ASSERT(bestsp[i] != cpu_to_be16(NULLDATAOFF));
if (be16_to_cpu(bestsp[i]) >= length) {
@ -810,14 +812,15 @@ xfs_dir2_leaf_addname(
memmove(&bestsp[0], &bestsp[1],
be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0]));
be32_add_cpu(&ltp->bestcount, 1);
xfs_dir3_leaf_log_tail(tp, lbp);
xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir3_leaf_log_tail(args, lbp);
xfs_dir3_leaf_log_bests(args, lbp, 0,
be32_to_cpu(ltp->bestcount) - 1);
}
/*
* If we're filling in a previously empty block just log it.
*/
else
xfs_dir3_leaf_log_bests(tp, lbp, use_block, use_block);
xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block);
hdr = dbp->b_addr;
bf = dp->d_ops->data_bestfree_p(hdr);
bestsp[use_block] = bf[0].length;
@ -828,8 +831,8 @@ xfs_dir2_leaf_addname(
* Just read that one in.
*/
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(mp, use_block),
-1, &dbp);
xfs_dir2_db_to_da(args->geo, use_block),
-1, &dbp);
if (error) {
xfs_trans_brelse(tp, lbp);
return error;
@ -848,7 +851,7 @@ xfs_dir2_leaf_addname(
/*
* Mark the initial part of our freespace in use for the new entry.
*/
xfs_dir2_data_use_free(tp, dp, dbp, dup,
xfs_dir2_data_use_free(args, dbp, dup,
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
&needlog, &needscan);
/*
@ -870,8 +873,8 @@ xfs_dir2_leaf_addname(
* Need to log the data block's header.
*/
if (needlog)
xfs_dir2_data_log_header(tp, dp, dbp);
xfs_dir2_data_log_entry(tp, dp, dbp, dep);
xfs_dir2_data_log_header(args, dbp);
xfs_dir2_data_log_entry(args, dbp, dep);
/*
* If the bests table needs to be changed, do it.
* Log the change unless we've already done that.
@ -879,7 +882,7 @@ xfs_dir2_leaf_addname(
if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(bf[0].length)) {
bestsp[use_block] = bf[0].length;
if (!grown)
xfs_dir3_leaf_log_bests(tp, lbp, use_block, use_block);
xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block);
}
lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale,
@ -889,14 +892,15 @@ xfs_dir2_leaf_addname(
* Fill in the new leaf entry.
*/
lep->hashval = cpu_to_be32(args->hashval);
lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp, use_block,
lep->address = cpu_to_be32(
xfs_dir2_db_off_to_dataptr(args->geo, use_block,
be16_to_cpu(*tagp)));
/*
* Log the leaf fields and give up the buffers.
*/
dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
xfs_dir3_leaf_log_header(tp, dp, lbp);
xfs_dir3_leaf_log_ents(tp, dp, lbp, lfloglow, lfloghigh);
xfs_dir3_leaf_log_header(args, lbp);
xfs_dir3_leaf_log_ents(args, lbp, lfloglow, lfloghigh);
xfs_dir3_leaf_check(dp, lbp);
xfs_dir3_data_check(dp, dbp);
return 0;
@ -948,9 +952,9 @@ xfs_dir3_leaf_compact(
leafhdr->stale = 0;
dp->d_ops->leaf_hdr_to_disk(leaf, leafhdr);
xfs_dir3_leaf_log_header(args->trans, dp, bp);
xfs_dir3_leaf_log_header(args, bp);
if (loglow != -1)
xfs_dir3_leaf_log_ents(args->trans, dp, bp, loglow, to - 1);
xfs_dir3_leaf_log_ents(args, bp, loglow, to - 1);
}
/*
@ -1052,7 +1056,7 @@ xfs_dir3_leaf_compact_x1(
*/
static void
xfs_dir3_leaf_log_bests(
xfs_trans_t *tp, /* transaction pointer */
struct xfs_da_args *args,
struct xfs_buf *bp, /* leaf buffer */
int first, /* first entry to log */
int last) /* last entry to log */
@ -1065,10 +1069,11 @@ xfs_dir3_leaf_log_bests(
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC));
ltp = xfs_dir2_leaf_tail_p(tp->t_mountp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
firstb = xfs_dir2_leaf_bests_p(ltp) + first;
lastb = xfs_dir2_leaf_bests_p(ltp) + last;
xfs_trans_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),
xfs_trans_log_buf(args->trans, bp,
(uint)((char *)firstb - (char *)leaf),
(uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));
}
@ -1077,8 +1082,7 @@ xfs_dir3_leaf_log_bests(
*/
void
xfs_dir3_leaf_log_ents(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp,
int first,
int last)
@ -1093,10 +1097,11 @@ xfs_dir3_leaf_log_ents(
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
ents = dp->d_ops->leaf_ents_p(leaf);
ents = args->dp->d_ops->leaf_ents_p(leaf);
firstlep = &ents[first];
lastlep = &ents[last];
xfs_trans_log_buf(tp, bp, (uint)((char *)firstlep - (char *)leaf),
xfs_trans_log_buf(args->trans, bp,
(uint)((char *)firstlep - (char *)leaf),
(uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1));
}
@ -1105,8 +1110,7 @@ xfs_dir3_leaf_log_ents(
*/
void
xfs_dir3_leaf_log_header(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp)
{
struct xfs_dir2_leaf *leaf = bp->b_addr;
@ -1116,8 +1120,9 @@ xfs_dir3_leaf_log_header(
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
xfs_trans_log_buf(tp, bp, (uint)((char *)&leaf->hdr - (char *)leaf),
dp->d_ops->leaf_hdr_size - 1);
xfs_trans_log_buf(args->trans, bp,
(uint)((char *)&leaf->hdr - (char *)leaf),
args->dp->d_ops->leaf_hdr_size - 1);
}
/*
@ -1125,21 +1130,20 @@ xfs_dir3_leaf_log_header(
*/
STATIC void
xfs_dir3_leaf_log_tail(
struct xfs_trans *tp,
struct xfs_da_args *args,
struct xfs_buf *bp)
{
struct xfs_dir2_leaf *leaf = bp->b_addr;
xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */
struct xfs_mount *mp = tp->t_mountp;
ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) ||
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) ||
leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC));
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
xfs_trans_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
(uint)(mp->m_dirblksize - 1));
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
xfs_trans_log_buf(args->trans, bp, (uint)((char *)ltp - (char *)leaf),
(uint)(args->geo->blksize - 1));
}
/*
@ -1185,7 +1189,7 @@ xfs_dir2_leaf_lookup(
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->b_addr +
xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
/*
* Return the found inode number & CI name if appropriate
*/
@ -1231,7 +1235,7 @@ xfs_dir2_leaf_lookup_int(
tp = args->trans;
mp = dp->i_mount;
error = xfs_dir3_leaf_read(tp, dp, mp->m_dirleafblk, -1, &lbp);
error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
if (error)
return error;
@ -1260,7 +1264,8 @@ xfs_dir2_leaf_lookup_int(
/*
* Get the new data block number.
*/
newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
newdb = xfs_dir2_dataptr_to_db(args->geo,
be32_to_cpu(lep->address));
/*
* If it's not the same as the old data block number,
* need to pitch the old one and read the new one.
@ -1269,8 +1274,8 @@ xfs_dir2_leaf_lookup_int(
if (dbp)
xfs_trans_brelse(tp, dbp);
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(mp, newdb),
-1, &dbp);
xfs_dir2_db_to_da(args->geo, newdb),
-1, &dbp);
if (error) {
xfs_trans_brelse(tp, lbp);
return error;
@ -1281,7 +1286,8 @@ xfs_dir2_leaf_lookup_int(
* Point to the data entry.
*/
dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr +
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(args->geo,
be32_to_cpu(lep->address)));
/*
* Compare name and if it's an exact match, return the index
* and buffer. If it's the first case-insensitive match, store
@ -1310,8 +1316,8 @@ xfs_dir2_leaf_lookup_int(
if (cidb != curdb) {
xfs_trans_brelse(tp, dbp);
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(mp, cidb),
-1, &dbp);
xfs_dir2_db_to_da(args->geo, cidb),
-1, &dbp);
if (error) {
xfs_trans_brelse(tp, lbp);
return error;
@ -1380,18 +1386,18 @@ xfs_dir2_leaf_removename(
* Point to the leaf entry, use that to point to the data entry.
*/
lep = &ents[index];
db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
dep = (xfs_dir2_data_entry_t *)
((char *)hdr + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
needscan = needlog = 0;
oldbest = be16_to_cpu(bf[0].length);
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
bestsp = xfs_dir2_leaf_bests_p(ltp);
ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
/*
* Mark the former data entry unused.
*/
xfs_dir2_data_make_free(tp, dp, dbp,
xfs_dir2_data_make_free(args, dbp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
/*
@ -1399,10 +1405,10 @@ xfs_dir2_leaf_removename(
*/
leafhdr.stale++;
dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
xfs_dir3_leaf_log_header(tp, dp, lbp);
xfs_dir3_leaf_log_header(args, lbp);
lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
xfs_dir3_leaf_log_ents(tp, dp, lbp, index, index);
xfs_dir3_leaf_log_ents(args, lbp, index, index);
/*
* Scan the freespace in the data block again if necessary,
@ -1411,22 +1417,22 @@ xfs_dir2_leaf_removename(
if (needscan)
xfs_dir2_data_freescan(dp, hdr, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dp, dbp);
xfs_dir2_data_log_header(args, dbp);
/*
* If the longest freespace in the data block has changed,
* put the new value in the bests table and log that.
*/
if (be16_to_cpu(bf[0].length) != oldbest) {
bestsp[db] = bf[0].length;
xfs_dir3_leaf_log_bests(tp, lbp, db, db);
xfs_dir3_leaf_log_bests(args, lbp, db, db);
}
xfs_dir3_data_check(dp, dbp);
/*
* If the data block is now empty then get rid of the data block.
*/
if (be16_to_cpu(bf[0].length) ==
mp->m_dirblksize - dp->d_ops->data_entry_offset) {
ASSERT(db != mp->m_dirdatablk);
args->geo->blksize - dp->d_ops->data_entry_offset) {
ASSERT(db != args->geo->datablk);
if ((error = xfs_dir2_shrink_inode(args, db, dbp))) {
/*
* Nope, can't get rid of it because it caused
@ -1459,15 +1465,16 @@ xfs_dir2_leaf_removename(
memmove(&bestsp[db - i], bestsp,
(be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp));
be32_add_cpu(&ltp->bestcount, -(db - i));
xfs_dir3_leaf_log_tail(tp, lbp);
xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir3_leaf_log_tail(args, lbp);
xfs_dir3_leaf_log_bests(args, lbp, 0,
be32_to_cpu(ltp->bestcount) - 1);
} else
bestsp[db] = cpu_to_be16(NULLDATAOFF);
}
/*
* If the data block was not the first one, drop it.
*/
else if (db != mp->m_dirdatablk)
else if (db != args->geo->datablk)
dbp = NULL;
xfs_dir3_leaf_check(dp, lbp);
@ -1515,7 +1522,7 @@ xfs_dir2_leaf_replace(
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->b_addr +
xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)));
ASSERT(args->inumber != be64_to_cpu(dep->inumber));
/*
* Put the new inode number in, log it.
@ -1523,7 +1530,7 @@ xfs_dir2_leaf_replace(
dep->inumber = cpu_to_be64(args->inumber);
dp->d_ops->data_put_ftype(dep, args->filetype);
tp = args->trans;
xfs_dir2_data_log_entry(tp, dp, dbp, dep);
xfs_dir2_data_log_entry(args, dbp, dep);
xfs_dir3_leaf_check(dp, lbp);
xfs_trans_brelse(tp, lbp);
return 0;
@ -1609,12 +1616,13 @@ xfs_dir2_leaf_trim_data(
/*
* Read the offending data block. We need its buffer.
*/
error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(mp, db), -1, &dbp);
error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, db),
-1, &dbp);
if (error)
return error;
leaf = lbp->b_addr;
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
#ifdef DEBUG
{
@ -1624,7 +1632,7 @@ xfs_dir2_leaf_trim_data(
ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
ASSERT(be16_to_cpu(bf[0].length) ==
mp->m_dirblksize - dp->d_ops->data_entry_offset);
args->geo->blksize - dp->d_ops->data_entry_offset);
ASSERT(db == be32_to_cpu(ltp->bestcount) - 1);
}
#endif
@ -1643,8 +1651,8 @@ xfs_dir2_leaf_trim_data(
bestsp = xfs_dir2_leaf_bests_p(ltp);
be32_add_cpu(&ltp->bestcount, -1);
memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp));
xfs_dir3_leaf_log_tail(tp, lbp);
xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir3_leaf_log_tail(args, lbp);
xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
return 0;
}
@ -1708,22 +1716,22 @@ xfs_dir2_node_to_leaf(
/*
* Get the last offset in the file.
*/
if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK))) {
if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) {
return error;
}
fo -= mp->m_dirblkfsbs;
fo -= args->geo->fsbcount;
/*
* If there are freespace blocks other than the first one,
* take this opportunity to remove trailing empty freespace blocks
* that may have been left behind during no-space-reservation
* operations.
*/
while (fo > mp->m_dirfreeblk) {
while (fo > args->geo->freeblk) {
if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) {
return error;
}
if (rval)
fo -= mp->m_dirblkfsbs;
fo -= args->geo->fsbcount;
else
return 0;
}
@ -1736,7 +1744,7 @@ xfs_dir2_node_to_leaf(
/*
* If it's not the single leaf block, give up.
*/
if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + mp->m_dirblksize)
if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + args->geo->blksize)
return 0;
lbp = state->path.blk[0].bp;
leaf = lbp->b_addr;
@ -1748,7 +1756,7 @@ xfs_dir2_node_to_leaf(
/*
* Read the freespace block.
*/
error = xfs_dir2_free_read(tp, dp, mp->m_dirfreeblk, &fbp);
error = xfs_dir2_free_read(tp, dp, args->geo->freeblk, &fbp);
if (error)
return error;
free = fbp->b_addr;
@ -1760,7 +1768,7 @@ xfs_dir2_node_to_leaf(
* Now see if the leafn and free data will fit in a leaf1.
* If not, release the buffer and give up.
*/
if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > mp->m_dirblksize) {
if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > args->geo->blksize) {
xfs_trans_brelse(tp, fbp);
return 0;
}
@ -1780,7 +1788,7 @@ xfs_dir2_node_to_leaf(
/*
* Set up the leaf tail from the freespace block.
*/
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
ltp->bestcount = cpu_to_be32(freehdr.nvalid);
/*
@ -1790,15 +1798,17 @@ xfs_dir2_node_to_leaf(
freehdr.nvalid * sizeof(xfs_dir2_data_off_t));
dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
xfs_dir3_leaf_log_header(tp, dp, lbp);
xfs_dir3_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir3_leaf_log_tail(tp, lbp);
xfs_dir3_leaf_log_header(args, lbp);
xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir3_leaf_log_tail(args, lbp);
xfs_dir3_leaf_check(dp, lbp);
/*
* Get rid of the freespace block.
*/
error = xfs_dir2_shrink_inode(args, XFS_DIR2_FREE_FIRSTDB(mp), fbp);
error = xfs_dir2_shrink_inode(args,
xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET),
fbp);
if (error) {
/*
* This can't fail here because it can only happen when

View file

@ -195,17 +195,18 @@ xfs_dir2_free_try_read(
static int
xfs_dir3_free_get_buf(
struct xfs_trans *tp,
struct xfs_inode *dp,
xfs_da_args_t *args,
xfs_dir2_db_t fbno,
struct xfs_buf **bpp)
{
struct xfs_trans *tp = args->trans;
struct xfs_inode *dp = args->dp;
struct xfs_mount *mp = dp->i_mount;
struct xfs_buf *bp;
int error;
struct xfs_dir3_icfree_hdr hdr;
error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fbno),
error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
-1, &bp, XFS_DATA_FORK);
if (error)
return error;
@ -240,8 +241,7 @@ xfs_dir3_free_get_buf(
*/
STATIC void
xfs_dir2_free_log_bests(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp,
int first, /* first entry to log */
int last) /* last entry to log */
@ -250,10 +250,10 @@ xfs_dir2_free_log_bests(
__be16 *bests;
free = bp->b_addr;
bests = dp->d_ops->free_bests_p(free);
bests = args->dp->d_ops->free_bests_p(free);
ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
xfs_trans_log_buf(tp, bp,
xfs_trans_log_buf(args->trans, bp,
(uint)((char *)&bests[first] - (char *)free),
(uint)((char *)&bests[last] - (char *)free +
sizeof(bests[0]) - 1));
@ -264,8 +264,7 @@ xfs_dir2_free_log_bests(
*/
static void
xfs_dir2_free_log_header(
struct xfs_trans *tp,
struct xfs_inode *dp,
struct xfs_da_args *args,
struct xfs_buf *bp)
{
#ifdef DEBUG
@ -275,7 +274,8 @@ xfs_dir2_free_log_header(
ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
#endif
xfs_trans_log_buf(tp, bp, 0, dp->d_ops->free_hdr_size - 1);
xfs_trans_log_buf(args->trans, bp, 0,
args->dp->d_ops->free_hdr_size - 1);
}
/*
@ -315,20 +315,20 @@ xfs_dir2_leaf_to_node(
if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) {
return error;
}
ASSERT(fdb == XFS_DIR2_FREE_FIRSTDB(mp));
ASSERT(fdb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
/*
* Get the buffer for the new freespace block.
*/
error = xfs_dir3_free_get_buf(tp, dp, fdb, &fbp);
error = xfs_dir3_free_get_buf(args, fdb, &fbp);
if (error)
return error;
free = fbp->b_addr;
dp->d_ops->free_hdr_from_disk(&freehdr, free);
leaf = lbp->b_addr;
ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp = xfs_dir2_leaf_tail_p(args->geo, leaf);
ASSERT(be32_to_cpu(ltp->bestcount) <=
(uint)dp->i_d.di_size / mp->m_dirblksize);
(uint)dp->i_d.di_size / args->geo->blksize);
/*
* Copy freespace entries from the leaf block to the new block.
@ -349,8 +349,8 @@ xfs_dir2_leaf_to_node(
freehdr.nvalid = be32_to_cpu(ltp->bestcount);
dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr);
xfs_dir2_free_log_bests(tp, dp, fbp, 0, freehdr.nvalid - 1);
xfs_dir2_free_log_header(tp, dp, fbp);
xfs_dir2_free_log_bests(args, fbp, 0, freehdr.nvalid - 1);
xfs_dir2_free_log_header(args, fbp);
/*
* Converting the leaf to a leafnode is just a matter of changing the
@ -364,7 +364,7 @@ xfs_dir2_leaf_to_node(
leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC);
lbp->b_ops = &xfs_dir3_leafn_buf_ops;
xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF);
xfs_dir3_leaf_log_header(tp, dp, lbp);
xfs_dir3_leaf_log_header(args, lbp);
xfs_dir3_leaf_check(dp, lbp);
return 0;
}
@ -415,7 +415,7 @@ xfs_dir2_leafn_add(
* a compact.
*/
if (leafhdr.count == dp->d_ops->leaf_max_ents(mp)) {
if (leafhdr.count == dp->d_ops->leaf_max_ents(args->geo)) {
if (!leafhdr.stale)
return XFS_ERROR(ENOSPC);
compact = leafhdr.stale > 1;
@ -450,12 +450,12 @@ xfs_dir2_leafn_add(
highstale, &lfloglow, &lfloghigh);
lep->hashval = cpu_to_be32(args->hashval);
lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp,
lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(args->geo,
args->blkno, args->index));
dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
xfs_dir3_leaf_log_header(tp, dp, bp);
xfs_dir3_leaf_log_ents(tp, dp, bp, lfloglow, lfloghigh);
xfs_dir3_leaf_log_header(args, bp);
xfs_dir3_leaf_log_ents(args, bp, lfloglow, lfloghigh);
xfs_dir3_leaf_check(dp, bp);
return 0;
}
@ -471,7 +471,8 @@ xfs_dir2_free_hdr_check(
dp->d_ops->free_hdr_from_disk(&hdr, bp->b_addr);
ASSERT((hdr.firstdb % dp->d_ops->free_max_bests(dp->i_mount)) == 0);
ASSERT((hdr.firstdb %
dp->d_ops->free_max_bests(dp->i_mount->m_dir_geo)) == 0);
ASSERT(hdr.firstdb <= db);
ASSERT(db < hdr.firstdb + hdr.nvalid);
}
@ -576,7 +577,8 @@ xfs_dir2_leafn_lookup_for_addname(
/*
* Pull the data block number from the entry.
*/
newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
newdb = xfs_dir2_dataptr_to_db(args->geo,
be32_to_cpu(lep->address));
/*
* For addname, we're looking for a place to put the new entry.
* We want to use a data block with an entry of equal
@ -593,7 +595,7 @@ xfs_dir2_leafn_lookup_for_addname(
* Convert the data block to the free block
* holding its freespace information.
*/
newfdb = dp->d_ops->db_to_fdb(mp, newdb);
newfdb = dp->d_ops->db_to_fdb(args->geo, newdb);
/*
* If it's not the one we have in hand, read it in.
*/
@ -605,7 +607,8 @@ xfs_dir2_leafn_lookup_for_addname(
xfs_trans_brelse(tp, curbp);
error = xfs_dir2_free_read(tp, dp,
xfs_dir2_db_to_da(mp, newfdb),
xfs_dir2_db_to_da(args->geo,
newfdb),
&curbp);
if (error)
return error;
@ -616,7 +619,7 @@ xfs_dir2_leafn_lookup_for_addname(
/*
* Get the index for our entry.
*/
fi = dp->d_ops->db_to_fdindex(mp, curdb);
fi = dp->d_ops->db_to_fdindex(args->geo, curdb);
/*
* If it has room, return it.
*/
@ -721,7 +724,8 @@ xfs_dir2_leafn_lookup_for_entry(
/*
* Pull the data block number from the entry.
*/
newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
newdb = xfs_dir2_dataptr_to_db(args->geo,
be32_to_cpu(lep->address));
/*
* Not adding a new entry, so we really want to find
* the name given to us.
@ -746,7 +750,8 @@ xfs_dir2_leafn_lookup_for_entry(
curbp = state->extrablk.bp;
} else {
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(mp, newdb),
xfs_dir2_db_to_da(args->geo,
newdb),
-1, &curbp);
if (error)
return error;
@ -758,7 +763,8 @@ xfs_dir2_leafn_lookup_for_entry(
* Point to the data entry.
*/
dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr +
xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(args->geo,
be32_to_cpu(lep->address)));
/*
* Compare the entry and if it's an exact match, return
* EEXIST immediately. If it's the first case-insensitive
@ -844,7 +850,6 @@ xfs_dir3_leafn_moveents(
int start_d,/* destination leaf index */
int count) /* count of leaves to copy */
{
struct xfs_trans *tp = args->trans;
int stale; /* count stale leaves copied */
trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count);
@ -863,7 +868,7 @@ xfs_dir3_leafn_moveents(
if (start_d < dhdr->count) {
memmove(&dents[start_d + count], &dents[start_d],
(dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir3_leaf_log_ents(tp, args->dp, bp_d, start_d + count,
xfs_dir3_leaf_log_ents(args, bp_d, start_d + count,
count + dhdr->count - 1);
}
/*
@ -885,8 +890,7 @@ xfs_dir3_leafn_moveents(
*/
memcpy(&dents[start_d], &sents[start_s],
count * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir3_leaf_log_ents(tp, args->dp, bp_d,
start_d, start_d + count - 1);
xfs_dir3_leaf_log_ents(args, bp_d, start_d, start_d + count - 1);
/*
* If there are source entries after the ones we copied,
@ -895,8 +899,7 @@ xfs_dir3_leafn_moveents(
if (start_s + count < shdr->count) {
memmove(&sents[start_s], &sents[start_s + count],
count * sizeof(xfs_dir2_leaf_entry_t));
xfs_dir3_leaf_log_ents(tp, args->dp, bp_s,
start_s, start_s + count - 1);
xfs_dir3_leaf_log_ents(args, bp_s, start_s, start_s + count - 1);
}
/*
@ -1032,8 +1035,8 @@ xfs_dir2_leafn_rebalance(
/* log the changes made when moving the entries */
dp->d_ops->leaf_hdr_to_disk(leaf1, &hdr1);
dp->d_ops->leaf_hdr_to_disk(leaf2, &hdr2);
xfs_dir3_leaf_log_header(args->trans, dp, blk1->bp);
xfs_dir3_leaf_log_header(args->trans, dp, blk2->bp);
xfs_dir3_leaf_log_header(args, blk1->bp);
xfs_dir3_leaf_log_header(args, blk2->bp);
xfs_dir3_leaf_check(dp, blk1->bp);
xfs_dir3_leaf_check(dp, blk2->bp);
@ -1076,7 +1079,6 @@ xfs_dir3_data_block_free(
struct xfs_buf *fbp,
int longest)
{
struct xfs_trans *tp = args->trans;
int logfree = 0;
__be16 *bests;
struct xfs_dir3_icfree_hdr freehdr;
@ -1090,7 +1092,7 @@ xfs_dir3_data_block_free(
* value.
*/
bests[findex] = cpu_to_be16(longest);
xfs_dir2_free_log_bests(tp, dp, fbp, findex, findex);
xfs_dir2_free_log_bests(args, fbp, findex, findex);
return 0;
}
@ -1118,7 +1120,7 @@ xfs_dir3_data_block_free(
}
dp->d_ops->free_hdr_to_disk(free, &freehdr);
xfs_dir2_free_log_header(tp, dp, fbp);
xfs_dir2_free_log_header(args, fbp);
/*
* If there are no useful entries left in the block, get rid of the
@ -1142,7 +1144,7 @@ xfs_dir3_data_block_free(
/* Log the free entry that changed, unless we got rid of it. */
if (logfree)
xfs_dir2_free_log_bests(tp, dp, fbp, findex, findex);
xfs_dir2_free_log_bests(args, fbp, findex, findex);
return 0;
}
@ -1193,9 +1195,9 @@ xfs_dir2_leafn_remove(
/*
* Extract the data block and offset from the entry.
*/
db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address));
ASSERT(dblk->blkno == db);
off = xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address));
off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address));
ASSERT(dblk->index == off);
/*
@ -1204,10 +1206,10 @@ xfs_dir2_leafn_remove(
*/
leafhdr.stale++;
dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr);
xfs_dir3_leaf_log_header(tp, dp, bp);
xfs_dir3_leaf_log_header(args, bp);
lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR);
xfs_dir3_leaf_log_ents(tp, dp, bp, index, index);
xfs_dir3_leaf_log_ents(args, bp, index, index);
/*
* Make the data entry free. Keep track of the longest freespace
@ -1219,7 +1221,7 @@ xfs_dir2_leafn_remove(
bf = dp->d_ops->data_bestfree_p(hdr);
longest = be16_to_cpu(bf[0].length);
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, dp, dbp, off,
xfs_dir2_data_make_free(args, dbp, off,
dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan);
/*
* Rescan the data block freespaces for bestfree.
@ -1228,7 +1230,7 @@ xfs_dir2_leafn_remove(
if (needscan)
xfs_dir2_data_freescan(dp, hdr, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dp, dbp);
xfs_dir2_data_log_header(args, dbp);
xfs_dir3_data_check(dp, dbp);
/*
* If the longest data block freespace changes, need to update
@ -1245,8 +1247,9 @@ xfs_dir2_leafn_remove(
* Convert the data block number to a free block,
* read in the free block.
*/
fdb = dp->d_ops->db_to_fdb(mp, db);
error = xfs_dir2_free_read(tp, dp, xfs_dir2_db_to_da(mp, fdb),
fdb = dp->d_ops->db_to_fdb(args->geo, db);
error = xfs_dir2_free_read(tp, dp,
xfs_dir2_db_to_da(args->geo, fdb),
&fbp);
if (error)
return error;
@ -1255,20 +1258,21 @@ xfs_dir2_leafn_remove(
{
struct xfs_dir3_icfree_hdr freehdr;
dp->d_ops->free_hdr_from_disk(&freehdr, free);
ASSERT(freehdr.firstdb == dp->d_ops->free_max_bests(mp) *
(fdb - XFS_DIR2_FREE_FIRSTDB(mp)));
ASSERT(freehdr.firstdb == dp->d_ops->free_max_bests(args->geo) *
(fdb - xfs_dir2_byte_to_db(args->geo,
XFS_DIR2_FREE_OFFSET)));
}
#endif
/*
* Calculate which entry we need to fix.
*/
findex = dp->d_ops->db_to_fdindex(mp, db);
findex = dp->d_ops->db_to_fdindex(args->geo, db);
longest = be16_to_cpu(bf[0].length);
/*
* If the data block is now empty we can get rid of it
* (usually).
*/
if (longest == mp->m_dirblksize -
if (longest == args->geo->blksize -
dp->d_ops->data_entry_offset) {
/*
* Try to punch out the data block.
@ -1303,7 +1307,7 @@ xfs_dir2_leafn_remove(
*/
*rval = (dp->d_ops->leaf_hdr_size +
(uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) <
mp->m_dir_magicpct;
args->geo->magicpct;
return 0;
}
@ -1336,7 +1340,7 @@ xfs_dir2_leafn_split(
/*
* Initialize the new leaf block.
*/
error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(mp, blkno),
error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(args->geo, blkno),
&newblk->bp, XFS_DIR2_LEAFN_MAGIC);
if (error)
return error;
@ -1410,7 +1414,7 @@ xfs_dir2_leafn_toosmall(
count = leafhdr.count - leafhdr.stale;
bytes = dp->d_ops->leaf_hdr_size + count * sizeof(ents[0]);
if (bytes > (state->blocksize >> 1)) {
if (bytes > (state->args->geo->blksize >> 1)) {
/*
* Blk over 50%, don't try to join.
*/
@ -1463,7 +1467,8 @@ xfs_dir2_leafn_toosmall(
* Count bytes in the two blocks combined.
*/
count = leafhdr.count - leafhdr.stale;
bytes = state->blocksize - (state->blocksize >> 2);
bytes = state->args->geo->blksize -
(state->args->geo->blksize >> 2);
leaf = bp->b_addr;
dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf);
@ -1560,8 +1565,8 @@ xfs_dir2_leafn_unbalance(
/* log the changes made when moving the entries */
dp->d_ops->leaf_hdr_to_disk(save_leaf, &savehdr);
dp->d_ops->leaf_hdr_to_disk(drop_leaf, &drophdr);
xfs_dir3_leaf_log_header(args->trans, dp, save_blk->bp);
xfs_dir3_leaf_log_header(args->trans, dp, drop_blk->bp);
xfs_dir3_leaf_log_header(args, save_blk->bp);
xfs_dir3_leaf_log_header(args, drop_blk->bp);
xfs_dir3_leaf_check(dp, save_blk->bp);
xfs_dir3_leaf_check(dp, drop_blk->bp);
@ -1587,8 +1592,6 @@ xfs_dir2_node_addname(
state = xfs_da_state_alloc();
state->args = args;
state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_dirblksize;
state->node_ents = state->mp->m_dir_node_ents;
/*
* Look up the name. We're not supposed to find it, but
* this gives us the insertion point.
@ -1727,9 +1730,9 @@ xfs_dir2_node_addname_int(
if (dbno == -1) {
xfs_fileoff_t fo; /* freespace block number */
if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK)))
if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK)))
return error;
lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo);
lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo);
fbno = ifbno;
}
/*
@ -1747,7 +1750,8 @@ xfs_dir2_node_addname_int(
* us a freespace block to start with.
*/
if (++fbno == 0)
fbno = XFS_DIR2_FREE_FIRSTDB(mp);
fbno = xfs_dir2_byte_to_db(args->geo,
XFS_DIR2_FREE_OFFSET);
/*
* If it's ifbno we already looked at it.
*/
@ -1765,8 +1769,8 @@ xfs_dir2_node_addname_int(
* to avoid it.
*/
error = xfs_dir2_free_try_read(tp, dp,
xfs_dir2_db_to_da(mp, fbno),
&fbp);
xfs_dir2_db_to_da(args->geo, fbno),
&fbp);
if (error)
return error;
if (!fbp)
@ -1834,10 +1838,10 @@ xfs_dir2_node_addname_int(
* Get the freespace block corresponding to the data block
* that was just allocated.
*/
fbno = dp->d_ops->db_to_fdb(mp, dbno);
fbno = dp->d_ops->db_to_fdb(args->geo, dbno);
error = xfs_dir2_free_try_read(tp, dp,
xfs_dir2_db_to_da(mp, fbno),
&fbp);
xfs_dir2_db_to_da(args->geo, fbno),
&fbp);
if (error)
return error;
@ -1851,12 +1855,13 @@ xfs_dir2_node_addname_int(
if (error)
return error;
if (unlikely(dp->d_ops->db_to_fdb(mp, dbno) != fbno)) {
if (dp->d_ops->db_to_fdb(args->geo, dbno) != fbno) {
xfs_alert(mp,
"%s: dir ino %llu needed freesp block %lld for\n"
" data block %lld, got %lld ifbno %llu lastfbno %d",
__func__, (unsigned long long)dp->i_ino,
(long long)dp->d_ops->db_to_fdb(mp, dbno),
(long long)dp->d_ops->db_to_fdb(
args->geo, dbno),
(long long)dbno, (long long)fbno,
(unsigned long long)ifbno, lastfbno);
if (fblk) {
@ -1877,7 +1882,7 @@ xfs_dir2_node_addname_int(
/*
* Get a buffer for the new block.
*/
error = xfs_dir3_free_get_buf(tp, dp, fbno, &fbp);
error = xfs_dir3_free_get_buf(args, fbno, &fbp);
if (error)
return error;
free = fbp->b_addr;
@ -1887,8 +1892,10 @@ xfs_dir2_node_addname_int(
/*
* Remember the first slot as our empty slot.
*/
freehdr.firstdb = (fbno - XFS_DIR2_FREE_FIRSTDB(mp)) *
dp->d_ops->free_max_bests(mp);
freehdr.firstdb =
(fbno - xfs_dir2_byte_to_db(args->geo,
XFS_DIR2_FREE_OFFSET)) *
dp->d_ops->free_max_bests(args->geo);
} else {
free = fbp->b_addr;
bests = dp->d_ops->free_bests_p(free);
@ -1898,13 +1905,13 @@ xfs_dir2_node_addname_int(
/*
* Set the freespace block index from the data block number.
*/
findex = dp->d_ops->db_to_fdindex(mp, dbno);
findex = dp->d_ops->db_to_fdindex(args->geo, dbno);
/*
* If it's after the end of the current entries in the
* freespace block, extend that table.
*/
if (findex >= freehdr.nvalid) {
ASSERT(findex < dp->d_ops->free_max_bests(mp));
ASSERT(findex < dp->d_ops->free_max_bests(args->geo));
freehdr.nvalid = findex + 1;
/*
* Tag new entry so nused will go up.
@ -1918,7 +1925,7 @@ xfs_dir2_node_addname_int(
if (bests[findex] == cpu_to_be16(NULLDATAOFF)) {
freehdr.nused++;
dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr);
xfs_dir2_free_log_header(tp, dp, fbp);
xfs_dir2_free_log_header(args, fbp);
}
/*
* Update the real value in the table.
@ -1943,7 +1950,8 @@ xfs_dir2_node_addname_int(
/*
* Read the data block in.
*/
error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(mp, dbno),
error = xfs_dir3_data_read(tp, dp,
xfs_dir2_db_to_da(args->geo, dbno),
-1, &dbp);
if (error)
return error;
@ -1961,7 +1969,7 @@ xfs_dir2_node_addname_int(
/*
* Mark the first part of the unused space, inuse for us.
*/
xfs_dir2_data_use_free(tp, dp, dbp, dup,
xfs_dir2_data_use_free(args, dbp, dup,
(xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length,
&needlog, &needscan);
/*
@ -1974,7 +1982,7 @@ xfs_dir2_node_addname_int(
dp->d_ops->data_put_ftype(dep, args->filetype);
tagp = dp->d_ops->data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)hdr);
xfs_dir2_data_log_entry(tp, dp, dbp, dep);
xfs_dir2_data_log_entry(args, dbp, dep);
/*
* Rescan the block for bestfree if needed.
*/
@ -1984,7 +1992,7 @@ xfs_dir2_node_addname_int(
* Log the data block header if needed.
*/
if (needlog)
xfs_dir2_data_log_header(tp, dp, dbp);
xfs_dir2_data_log_header(args, dbp);
/*
* If the freespace entry is now wrong, update it.
*/
@ -1997,7 +2005,7 @@ xfs_dir2_node_addname_int(
* Log the freespace entry if needed.
*/
if (logfree)
xfs_dir2_free_log_bests(tp, dp, fbp, findex, findex);
xfs_dir2_free_log_bests(args, fbp, findex, findex);
/*
* Return the data block and offset in args, then drop the data block.
*/
@ -2028,8 +2036,6 @@ xfs_dir2_node_lookup(
state = xfs_da_state_alloc();
state->args = args;
state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_dirblksize;
state->node_ents = state->mp->m_dir_node_ents;
/*
* Fill in the path to the entry in the cursor.
*/
@ -2083,8 +2089,6 @@ xfs_dir2_node_removename(
state = xfs_da_state_alloc();
state->args = args;
state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_dirblksize;
state->node_ents = state->mp->m_dir_node_ents;
/* Look up the entry we're deleting, set up the cursor. */
error = xfs_da3_node_lookup_int(state, &rval);
@ -2153,8 +2157,6 @@ xfs_dir2_node_replace(
state = xfs_da_state_alloc();
state->args = args;
state->mp = args->dp->i_mount;
state->blocksize = state->mp->m_dirblksize;
state->node_ents = state->mp->m_dir_node_ents;
inum = args->inumber;
/*
* Lookup the entry to change in the btree.
@ -2186,15 +2188,15 @@ xfs_dir2_node_replace(
hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC));
dep = (xfs_dir2_data_entry_t *)
((char *)hdr +
xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address)));
xfs_dir2_dataptr_to_off(args->geo,
be32_to_cpu(lep->address)));
ASSERT(inum != be64_to_cpu(dep->inumber));
/*
* Fill in the new inode number and log the entry.
*/
dep->inumber = cpu_to_be64(inum);
args->dp->d_ops->data_put_ftype(dep, args->filetype);
xfs_dir2_data_log_entry(args->trans, args->dp,
state->extrablk.bp, dep);
xfs_dir2_data_log_entry(args, state->extrablk.bp, dep);
rval = 0;
}
/*
@ -2262,9 +2264,9 @@ xfs_dir2_node_trim_free(
/*
* Blow the block away.
*/
if ((error =
xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo),
bp))) {
error = xfs_dir2_shrink_inode(args,
xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo), bp);
if (error) {
/*
* Can't fail with ENOSPC since that only happens with no
* space reservation, when breaking up an extent into two

View file

@ -20,6 +20,140 @@
struct dir_context;
/*
* Directory offset/block conversion functions.
*
* DB blocks here are logical directory block numbers, not filesystem blocks.
*/
/*
* Convert dataptr to byte in file space
*/
static inline xfs_dir2_off_t
xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp)
{
return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG;
}
/*
* Convert byte in file space to dataptr. It had better be aligned.
*/
static inline xfs_dir2_dataptr_t
xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by)
{
return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG);
}
/*
* Convert byte in space to (DB) block
*/
static inline xfs_dir2_db_t
xfs_dir2_byte_to_db(struct xfs_da_geometry *geo, xfs_dir2_off_t by)
{
return (xfs_dir2_db_t)(by >> geo->blklog);
}
/*
* Convert dataptr to a block number
*/
static inline xfs_dir2_db_t
xfs_dir2_dataptr_to_db(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp)
{
return xfs_dir2_byte_to_db(geo, xfs_dir2_dataptr_to_byte(dp));
}
/*
* Convert byte in space to offset in a block
*/
static inline xfs_dir2_data_aoff_t
xfs_dir2_byte_to_off(struct xfs_da_geometry *geo, xfs_dir2_off_t by)
{
return (xfs_dir2_data_aoff_t)(by & (geo->blksize - 1));
}
/*
* Convert dataptr to a byte offset in a block
*/
static inline xfs_dir2_data_aoff_t
xfs_dir2_dataptr_to_off(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp)
{
return xfs_dir2_byte_to_off(geo, xfs_dir2_dataptr_to_byte(dp));
}
/*
* Convert block and offset to byte in space
*/
static inline xfs_dir2_off_t
xfs_dir2_db_off_to_byte(struct xfs_da_geometry *geo, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
{
return ((xfs_dir2_off_t)db << geo->blklog) + o;
}
/*
* Convert block (DB) to block (dablk)
*/
static inline xfs_dablk_t
xfs_dir2_db_to_da(struct xfs_da_geometry *geo, xfs_dir2_db_t db)
{
return (xfs_dablk_t)(db << (geo->blklog - geo->fsblog));
}
/*
* Convert byte in space to (DA) block
*/
static inline xfs_dablk_t
xfs_dir2_byte_to_da(struct xfs_da_geometry *geo, xfs_dir2_off_t by)
{
return xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, by));
}
/*
* Convert block and offset to dataptr
*/
static inline xfs_dir2_dataptr_t
xfs_dir2_db_off_to_dataptr(struct xfs_da_geometry *geo, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
{
return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(geo, db, o));
}
/*
* Convert block (dablk) to block (DB)
*/
static inline xfs_dir2_db_t
xfs_dir2_da_to_db(struct xfs_da_geometry *geo, xfs_dablk_t da)
{
return (xfs_dir2_db_t)(da >> (geo->blklog - geo->fsblog));
}
/*
* Convert block (dablk) to byte offset in space
*/
static inline xfs_dir2_off_t
xfs_dir2_da_to_byte(struct xfs_da_geometry *geo, xfs_dablk_t da)
{
return xfs_dir2_db_off_to_byte(geo, xfs_dir2_da_to_db(geo, da), 0);
}
/*
* Directory tail pointer accessor functions. Based on block geometry.
*/
static inline struct xfs_dir2_block_tail *
xfs_dir2_block_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr)
{
return ((struct xfs_dir2_block_tail *)
((char *)hdr + geo->blksize)) - 1;
}
static inline struct xfs_dir2_leaf_tail *
xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp)
{
return (struct xfs_dir2_leaf_tail *)
((char *)lp + geo->blksize -
sizeof(struct xfs_dir2_leaf_tail));
}
/* xfs_dir2.c */
extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
@ -54,8 +188,8 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp);
extern int xfs_dir3_data_readahead(struct xfs_trans *tp, struct xfs_inode *dp,
xfs_dablk_t bno, xfs_daddr_t mapped_bno);
extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno,
xfs_daddr_t mapped_bno);
extern struct xfs_dir2_data_free *
xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr,
@ -77,9 +211,9 @@ extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr,
int *lowstalep, int *highstalep, int *lowlogp, int *highlogp);
extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno,
struct xfs_buf **bpp, __uint16_t magic);
extern void xfs_dir3_leaf_log_ents(struct xfs_trans *tp, struct xfs_inode *dp,
extern void xfs_dir3_leaf_log_ents(struct xfs_da_args *args,
struct xfs_buf *bp, int first, int last);
extern void xfs_dir3_leaf_log_header(struct xfs_trans *tp, struct xfs_inode *dp,
extern void xfs_dir3_leaf_log_header(struct xfs_da_args *args,
struct xfs_buf *bp);
extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args);
extern int xfs_dir2_leaf_removename(struct xfs_da_args *args);

View file

@ -76,26 +76,25 @@ const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
STATIC int
xfs_dir2_sf_getdents(
xfs_inode_t *dp, /* incore directory inode */
struct xfs_da_args *args,
struct dir_context *ctx)
{
int i; /* shortform entry number */
xfs_mount_t *mp; /* filesystem mount point */
struct xfs_inode *dp = args->dp; /* incore directory inode */
xfs_dir2_dataptr_t off; /* current entry's offset */
xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */
xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
xfs_dir2_dataptr_t dot_offset;
xfs_dir2_dataptr_t dotdot_offset;
xfs_ino_t ino;
mp = dp->i_mount;
struct xfs_da_geometry *geo = args->geo;
ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
/*
* Give up if the directory is way too short.
*/
if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount));
return XFS_ERROR(EIO);
}
@ -109,18 +108,18 @@ xfs_dir2_sf_getdents(
/*
* If the block number in the offset is out of range, we're done.
*/
if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
return 0;
/*
* Precalculate offsets for . and .. as we will always need them.
*
* XXX(hch): the second argument is sometimes 0 and sometimes
* mp->m_dirdatablk.
* geo->datablk
*/
dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
dot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
dp->d_ops->data_dot_offset);
dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
dotdot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
dp->d_ops->data_dotdot_offset);
/*
@ -149,7 +148,7 @@ xfs_dir2_sf_getdents(
for (i = 0; i < sfp->count; i++) {
__uint8_t filetype;
off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
xfs_dir2_sf_get_offset(sfep));
if (ctx->pos > off) {
@ -161,13 +160,13 @@ xfs_dir2_sf_getdents(
filetype = dp->d_ops->sf_get_ftype(sfep);
ctx->pos = off & 0x7fffffff;
if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
xfs_dir3_get_dtype(mp, filetype)))
xfs_dir3_get_dtype(dp->i_mount, filetype)))
return 0;
sfep = dp->d_ops->sf_nextentry(sfp, sfep);
}
ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
0x7fffffff;
ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
0x7fffffff;
return 0;
}
@ -176,9 +175,10 @@ xfs_dir2_sf_getdents(
*/
STATIC int
xfs_dir2_block_getdents(
xfs_inode_t *dp, /* incore inode */
struct xfs_da_args *args,
struct dir_context *ctx)
{
struct xfs_inode *dp = args->dp; /* incore directory inode */
xfs_dir2_data_hdr_t *hdr; /* block header */
struct xfs_buf *bp; /* buffer for block */
xfs_dir2_block_tail_t *btp; /* block tail */
@ -186,16 +186,15 @@ xfs_dir2_block_getdents(
xfs_dir2_data_unused_t *dup; /* block unused entry */
char *endptr; /* end of the data entries */
int error; /* error return value */
xfs_mount_t *mp; /* filesystem mount point */
char *ptr; /* current data entry */
int wantoff; /* starting block offset */
xfs_off_t cook;
struct xfs_da_geometry *geo = args->geo;
mp = dp->i_mount;
/*
* If the block number in the offset is out of range, we're done.
*/
if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk)
return 0;
error = xfs_dir3_block_read(NULL, dp, &bp);
@ -206,13 +205,13 @@ xfs_dir2_block_getdents(
* Extract the byte offset we start at from the seek pointer.
* We'll skip entries before this.
*/
wantoff = xfs_dir2_dataptr_to_off(mp, ctx->pos);
wantoff = xfs_dir2_dataptr_to_off(geo, ctx->pos);
hdr = bp->b_addr;
xfs_dir3_data_check(dp, bp);
/*
* Set up values for the loop.
*/
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(geo, hdr);
ptr = (char *)dp->d_ops->data_entry_p(hdr);
endptr = (char *)xfs_dir2_block_leaf_p(btp);
@ -244,7 +243,7 @@ xfs_dir2_block_getdents(
if ((char *)dep - (char *)hdr < wantoff)
continue;
cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk,
(char *)dep - (char *)hdr);
ctx->pos = cook & 0x7fffffff;
@ -254,7 +253,7 @@ xfs_dir2_block_getdents(
*/
if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
be64_to_cpu(dep->inumber),
xfs_dir3_get_dtype(mp, filetype))) {
xfs_dir3_get_dtype(dp->i_mount, filetype))) {
xfs_trans_brelse(NULL, bp);
return 0;
}
@ -264,8 +263,8 @@ xfs_dir2_block_getdents(
* Reached the end of the block.
* Set the offset to a non-existent block 1 and return.
*/
ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
0x7fffffff;
ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) &
0x7fffffff;
xfs_trans_brelse(NULL, bp);
return 0;
}
@ -286,13 +285,13 @@ struct xfs_dir2_leaf_map_info {
STATIC int
xfs_dir2_leaf_readbuf(
struct xfs_inode *dp,
struct xfs_da_args *args,
size_t bufsize,
struct xfs_dir2_leaf_map_info *mip,
xfs_dir2_off_t *curoff,
struct xfs_buf **bpp)
{
struct xfs_mount *mp = dp->i_mount;
struct xfs_inode *dp = args->dp;
struct xfs_buf *bp = *bpp;
struct xfs_bmbt_irec *map = mip->map;
struct blk_plug plug;
@ -300,6 +299,7 @@ xfs_dir2_leaf_readbuf(
int length;
int i;
int j;
struct xfs_da_geometry *geo = args->geo;
/*
* If we have a buffer, we need to release it and
@ -309,12 +309,12 @@ xfs_dir2_leaf_readbuf(
if (bp) {
xfs_trans_brelse(NULL, bp);
bp = NULL;
mip->map_blocks -= mp->m_dirblkfsbs;
mip->map_blocks -= geo->fsbcount;
/*
* Loop to get rid of the extents for the
* directory block.
*/
for (i = mp->m_dirblkfsbs; i > 0; ) {
for (i = geo->fsbcount; i > 0; ) {
j = min_t(int, map->br_blockcount, i);
map->br_blockcount -= j;
map->br_startblock += j;
@ -333,8 +333,7 @@ xfs_dir2_leaf_readbuf(
/*
* Recalculate the readahead blocks wanted.
*/
mip->ra_want = howmany(bufsize + mp->m_dirblksize,
mp->m_sb.sb_blocksize) - 1;
mip->ra_want = howmany(bufsize + geo->blksize, (1 << geo->fsblog)) - 1;
ASSERT(mip->ra_want >= 0);
/*
@ -342,14 +341,14 @@ xfs_dir2_leaf_readbuf(
* run out of data blocks, get some more mappings.
*/
if (1 + mip->ra_want > mip->map_blocks &&
mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
mip->map_off < xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET)) {
/*
* Get more bmaps, fill in after the ones
* we already have in the table.
*/
mip->nmap = mip->map_size - mip->map_valid;
error = xfs_bmapi_read(dp, mip->map_off,
xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET) -
mip->map_off,
&map[mip->map_valid], &mip->nmap, 0);
@ -370,7 +369,7 @@ xfs_dir2_leaf_readbuf(
i = mip->map_valid + mip->nmap - 1;
mip->map_off = map[i].br_startoff + map[i].br_blockcount;
} else
mip->map_off = xfs_dir2_byte_to_da(mp,
mip->map_off = xfs_dir2_byte_to_da(geo,
XFS_DIR2_LEAF_OFFSET);
/*
@ -396,18 +395,18 @@ xfs_dir2_leaf_readbuf(
* No valid mappings, so no more data blocks.
*/
if (!mip->map_valid) {
*curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
*curoff = xfs_dir2_da_to_byte(geo, mip->map_off);
goto out;
}
/*
* Read the directory block starting at the first mapping.
*/
mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
mip->curdb = xfs_dir2_da_to_db(geo, map->br_startoff);
error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
map->br_blockcount >= mp->m_dirblkfsbs ?
XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
map->br_blockcount >= geo->fsbcount ?
XFS_FSB_TO_DADDR(dp->i_mount, map->br_startblock) :
-1, &bp);
/*
* Should just skip over the data block instead of giving up.
*/
@ -419,7 +418,7 @@ xfs_dir2_leaf_readbuf(
* was previously ra.
*/
if (mip->ra_current)
mip->ra_current -= mp->m_dirblkfsbs;
mip->ra_current -= geo->fsbcount;
/*
* Do we need more readahead?
@ -427,16 +426,16 @@ xfs_dir2_leaf_readbuf(
blk_start_plug(&plug);
for (mip->ra_index = mip->ra_offset = i = 0;
mip->ra_want > mip->ra_current && i < mip->map_blocks;
i += mp->m_dirblkfsbs) {
i += geo->fsbcount) {
ASSERT(mip->ra_index < mip->map_valid);
/*
* Read-ahead a contiguous directory block.
*/
if (i > mip->ra_current &&
map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
xfs_dir3_data_readahead(NULL, dp,
map[mip->ra_index].br_blockcount >= geo->fsbcount) {
xfs_dir3_data_readahead(dp,
map[mip->ra_index].br_startoff + mip->ra_offset,
XFS_FSB_TO_DADDR(mp,
XFS_FSB_TO_DADDR(dp->i_mount,
map[mip->ra_index].br_startblock +
mip->ra_offset));
mip->ra_current = i;
@ -447,7 +446,7 @@ xfs_dir2_leaf_readbuf(
* use our mapping, but this is a very rare case.
*/
else if (i > mip->ra_current) {
xfs_dir3_data_readahead(NULL, dp,
xfs_dir3_data_readahead(dp,
map[mip->ra_index].br_startoff +
mip->ra_offset, -1);
mip->ra_current = i;
@ -456,15 +455,14 @@ xfs_dir2_leaf_readbuf(
/*
* Advance offset through the mapping table.
*/
for (j = 0; j < mp->m_dirblkfsbs; j++) {
for (j = 0; j < geo->fsbcount; j += length ) {
/*
* The rest of this extent but not more than a dir
* block.
*/
length = min_t(int, mp->m_dirblkfsbs,
length = min_t(int, geo->fsbcount,
map[mip->ra_index].br_blockcount -
mip->ra_offset);
j += length;
mip->ra_offset += length;
/*
@ -489,22 +487,23 @@ xfs_dir2_leaf_readbuf(
*/
STATIC int
xfs_dir2_leaf_getdents(
xfs_inode_t *dp, /* incore directory inode */
struct xfs_da_args *args,
struct dir_context *ctx,
size_t bufsize)
{
struct xfs_inode *dp = args->dp;
struct xfs_buf *bp = NULL; /* data block buffer */
xfs_dir2_data_hdr_t *hdr; /* data block header */
xfs_dir2_data_entry_t *dep; /* data entry */
xfs_dir2_data_unused_t *dup; /* unused entry */
int error = 0; /* error return value */
int length; /* temporary length value */
xfs_mount_t *mp; /* filesystem mount point */
int byteoff; /* offset in current block */
xfs_dir2_off_t curoff; /* current overall offset */
xfs_dir2_off_t newoff; /* new curoff after new blk */
char *ptr = NULL; /* pointer to current data */
struct xfs_dir2_leaf_map_info *map_info;
struct xfs_da_geometry *geo = args->geo;
/*
* If the offset is at or past the largest allowed value,
@ -513,15 +512,12 @@ xfs_dir2_leaf_getdents(
if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
return 0;
mp = dp->i_mount;
/*
* Set up to bmap a number of blocks based on the caller's
* buffer size, the directory block size, and the filesystem
* block size.
*/
length = howmany(bufsize + mp->m_dirblksize,
mp->m_sb.sb_blocksize);
length = howmany(bufsize + geo->blksize, (1 << geo->fsblog));
map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
(length * sizeof(struct xfs_bmbt_irec)),
KM_SLEEP | KM_NOFS);
@ -531,14 +527,14 @@ xfs_dir2_leaf_getdents(
* Inside the loop we keep the main offset value as a byte offset
* in the directory file.
*/
curoff = xfs_dir2_dataptr_to_byte(mp, ctx->pos);
curoff = xfs_dir2_dataptr_to_byte(ctx->pos);
/*
* Force this conversion through db so we truncate the offset
* down to get the start of the data block.
*/
map_info->map_off = xfs_dir2_db_to_da(mp,
xfs_dir2_byte_to_db(mp, curoff));
map_info->map_off = xfs_dir2_db_to_da(geo,
xfs_dir2_byte_to_db(geo, curoff));
/*
* Loop over directory entries until we reach the end offset.
@ -551,9 +547,9 @@ xfs_dir2_leaf_getdents(
* If we have no buffer, or we're off the end of the
* current buffer, need to get another one.
*/
if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) {
error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
error = xfs_dir2_leaf_readbuf(args, bufsize, map_info,
&curoff, &bp);
if (error || !map_info->map_valid)
break;
@ -561,7 +557,8 @@ xfs_dir2_leaf_getdents(
/*
* Having done a read, we need to set a new offset.
*/
newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
newoff = xfs_dir2_db_off_to_byte(geo,
map_info->curdb, 0);
/*
* Start of the current block.
*/
@ -571,7 +568,7 @@ xfs_dir2_leaf_getdents(
* Make sure we're in the right block.
*/
else if (curoff > newoff)
ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
ASSERT(xfs_dir2_byte_to_db(geo, curoff) ==
map_info->curdb);
hdr = bp->b_addr;
xfs_dir3_data_check(dp, bp);
@ -579,7 +576,7 @@ xfs_dir2_leaf_getdents(
* Find our position in the block.
*/
ptr = (char *)dp->d_ops->data_entry_p(hdr);
byteoff = xfs_dir2_byte_to_off(mp, curoff);
byteoff = xfs_dir2_byte_to_off(geo, curoff);
/*
* Skip past the header.
*/
@ -608,10 +605,10 @@ xfs_dir2_leaf_getdents(
* Now set our real offset.
*/
curoff =
xfs_dir2_db_off_to_byte(mp,
xfs_dir2_byte_to_db(mp, curoff),
xfs_dir2_db_off_to_byte(geo,
xfs_dir2_byte_to_db(geo, curoff),
(char *)ptr - (char *)hdr);
if (ptr >= (char *)hdr + mp->m_dirblksize) {
if (ptr >= (char *)hdr + geo->blksize) {
continue;
}
}
@ -635,10 +632,10 @@ xfs_dir2_leaf_getdents(
length = dp->d_ops->data_entsize(dep->namelen);
filetype = dp->d_ops->data_get_ftype(dep);
ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
be64_to_cpu(dep->inumber),
xfs_dir3_get_dtype(mp, filetype)))
xfs_dir3_get_dtype(dp->i_mount, filetype)))
break;
/*
@ -653,10 +650,10 @@ xfs_dir2_leaf_getdents(
/*
* All done. Set output offset value to current offset.
*/
if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
if (curoff > xfs_dir2_dataptr_to_byte(XFS_DIR2_MAX_DATAPTR))
ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
else
ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff;
kmem_free(map_info);
if (bp)
xfs_trans_brelse(NULL, bp);
@ -668,13 +665,14 @@ xfs_dir2_leaf_getdents(
*/
int
xfs_readdir(
xfs_inode_t *dp,
struct dir_context *ctx,
size_t bufsize)
struct xfs_inode *dp,
struct dir_context *ctx,
size_t bufsize)
{
int rval; /* return value */
int v; /* type-checking value */
uint lock_mode;
struct xfs_da_args args = { NULL };
int rval;
int v;
uint lock_mode;
trace_xfs_readdir(dp);
@ -684,15 +682,18 @@ xfs_readdir(
ASSERT(S_ISDIR(dp->i_d.di_mode));
XFS_STATS_INC(xs_dir_getdents);
args.dp = dp;
args.geo = dp->i_mount->m_dir_geo;
lock_mode = xfs_ilock_data_map_shared(dp);
if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
rval = xfs_dir2_sf_getdents(dp, ctx);
else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
rval = xfs_dir2_sf_getdents(&args, ctx);
else if ((rval = xfs_dir2_isblock(&args, &v)))
;
else if (v)
rval = xfs_dir2_block_getdents(dp, ctx);
rval = xfs_dir2_block_getdents(&args, ctx);
else
rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize);
rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize);
xfs_iunlock(dp, lock_mode);
return rval;

View file

@ -82,8 +82,10 @@ xfs_dir2_block_sfsize(
xfs_ino_t parent = 0; /* parent inode number */
int size=0; /* total computed size */
int has_ftype;
struct xfs_da_geometry *geo;
mp = dp->i_mount;
geo = mp->m_dir_geo;
/*
* if there is a filetype field, add the extra byte to the namelen
@ -92,7 +94,7 @@ xfs_dir2_block_sfsize(
has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
count = i8count = namelen = 0;
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(geo, hdr);
blp = xfs_dir2_block_leaf_p(btp);
/*
@ -104,8 +106,8 @@ xfs_dir2_block_sfsize(
/*
* Calculate the pointer to the entry at hand.
*/
dep = (xfs_dir2_data_entry_t *)
((char *)hdr + xfs_dir2_dataptr_to_off(mp, addr));
dep = (xfs_dir2_data_entry_t *)((char *)hdr +
xfs_dir2_dataptr_to_off(geo, addr));
/*
* Detect . and .., so we can special-case them.
* . is not included in sf directories.
@ -195,7 +197,7 @@ xfs_dir2_block_to_sf(
/*
* Set up to loop over the block's entries.
*/
btp = xfs_dir2_block_tail_p(mp, hdr);
btp = xfs_dir2_block_tail_p(args->geo, hdr);
ptr = (char *)dp->d_ops->data_entry_p(hdr);
endptr = (char *)xfs_dir2_block_leaf_p(btp);
sfep = xfs_dir2_sf_firstentry(sfp);
@ -247,7 +249,7 @@ xfs_dir2_block_to_sf(
/* now we are done with the block, we can shrink the inode */
logflags = XFS_ILOG_CORE;
error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp);
error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp);
if (error) {
ASSERT(error != ENOSPC);
goto out;
@ -285,14 +287,12 @@ int /* error */
xfs_dir2_sf_addname(
xfs_da_args_t *args) /* operation arguments */
{
int add_entsize; /* size of the new entry */
xfs_inode_t *dp; /* incore directory inode */
int error; /* error return value */
int incr_isize; /* total change in size */
int new_isize; /* di_size after adding name */
int objchange; /* changing to 8-byte inodes */
xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */
int old_isize; /* di_size before adding name */
int pick; /* which algorithm to use */
xfs_dir2_sf_hdr_t *sfp; /* shortform structure */
xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */
@ -316,8 +316,7 @@ xfs_dir2_sf_addname(
/*
* Compute entry (and change in) size.
*/
add_entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
incr_isize = add_entsize;
incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen);
objchange = 0;
#if XFS_BIG_INUMS
/*
@ -325,11 +324,8 @@ xfs_dir2_sf_addname(
*/
if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) {
/*
* Yes, adjust the entry size and the total size.
* Yes, adjust the inode size. old count + (parent + new)
*/
add_entsize +=
(uint)sizeof(xfs_dir2_ino8_t) -
(uint)sizeof(xfs_dir2_ino4_t);
incr_isize +=
(sfp->count + 2) *
((uint)sizeof(xfs_dir2_ino8_t) -
@ -337,8 +333,7 @@ xfs_dir2_sf_addname(
objchange = 1;
}
#endif
old_isize = (int)dp->i_d.di_size;
new_isize = old_isize + incr_isize;
new_isize = (int)dp->i_d.di_size + incr_isize;
/*
* Won't fit as shortform any more (due to size),
* or the pick routine says it won't (due to offset values).
@ -593,7 +588,7 @@ xfs_dir2_sf_addname_pick(
* we'll go back, convert to block, then try the insert and convert
* to leaf.
*/
if (used + (holefit ? 0 : size) > mp->m_dirblksize)
if (used + (holefit ? 0 : size) > args->geo->blksize)
return 0;
/*
* If changing the inode number size, do it the hard way.
@ -608,7 +603,7 @@ xfs_dir2_sf_addname_pick(
/*
* If it won't fit at the end then do it the hard way (use the hole).
*/
if (used + size > mp->m_dirblksize)
if (used + size > args->geo->blksize)
return 2;
/*
* Do it the easy way.
@ -659,7 +654,7 @@ xfs_dir2_sf_check(
ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
ASSERT(offset +
(sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
(uint)sizeof(xfs_dir2_block_tail_t) <= mp->m_dirblksize);
(uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize);
}
#endif /* DEBUG */
@ -1110,9 +1105,9 @@ xfs_dir2_sf_toino4(
}
/*
* Convert from 4-byte inode numbers to 8-byte inode numbers.
* The new 8-byte inode number is not there yet, we leave with the
* count 1 but no corresponding entry.
* Convert existing entries from 4-byte inode numbers to 8-byte inode numbers.
* The new entry w/ an 8-byte inode number is not there yet; we leave with
* i8count set to 1, but no corresponding 8-byte entry.
*/
static void
xfs_dir2_sf_toino8(
@ -1145,7 +1140,7 @@ xfs_dir2_sf_toino8(
ASSERT(oldsfp->i8count == 0);
memcpy(buf, oldsfp, oldsize);
/*
* Compute the new inode size.
* Compute the new inode size (nb: entry count + 1 for parent)
*/
newsize =
oldsize +

View file

@ -353,10 +353,10 @@ xfs_qm_dqalloc(
dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen,
0);
error = xfs_buf_geterror(bp);
if (error)
if (!bp) {
error = ENOMEM;
goto error1;
}
bp->b_ops = &xfs_dquot_buf_ops;
/*
@ -832,47 +832,6 @@ xfs_qm_dqget(
return (0);
}
STATIC void
xfs_qm_dqput_final(
struct xfs_dquot *dqp)
{
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
struct xfs_dquot *gdqp;
struct xfs_dquot *pdqp;
trace_xfs_dqput_free(dqp);
if (list_lru_add(&qi->qi_lru, &dqp->q_lru))
XFS_STATS_INC(xs_qm_dquot_unused);
/*
* If we just added a udquot to the freelist, then we want to release
* the gdquot/pdquot reference that it (probably) has. Otherwise it'll
* keep the gdquot/pdquot from getting reclaimed.
*/
gdqp = dqp->q_gdquot;
if (gdqp) {
xfs_dqlock(gdqp);
dqp->q_gdquot = NULL;
}
pdqp = dqp->q_pdquot;
if (pdqp) {
xfs_dqlock(pdqp);
dqp->q_pdquot = NULL;
}
xfs_dqunlock(dqp);
/*
* If we had a group/project quota hint, release it now.
*/
if (gdqp)
xfs_qm_dqput(gdqp);
if (pdqp)
xfs_qm_dqput(pdqp);
}
/*
* Release a reference to the dquot (decrement ref-count) and unlock it.
*
@ -888,10 +847,14 @@ xfs_qm_dqput(
trace_xfs_dqput(dqp);
if (--dqp->q_nrefs > 0)
xfs_dqunlock(dqp);
else
xfs_qm_dqput_final(dqp);
if (--dqp->q_nrefs == 0) {
struct xfs_quotainfo *qi = dqp->q_mount->m_quotainfo;
trace_xfs_dqput_free(dqp);
if (list_lru_add(&qi->qi_lru, &dqp->q_lru))
XFS_STATS_INC(xs_qm_dquot_unused);
}
xfs_dqunlock(dqp);
}
/*

View file

@ -52,8 +52,6 @@ typedef struct xfs_dquot {
int q_bufoffset; /* off of dq in buffer (# dquots) */
xfs_fileoff_t q_fileoffset; /* offset in quotas file */
struct xfs_dquot*q_gdquot; /* group dquot, hint only */
struct xfs_dquot*q_pdquot; /* project dquot, hint only */
xfs_disk_dquot_t q_core; /* actual usage & quotas */
xfs_dq_logitem_t q_logitem; /* dquot log item */
xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */

View file

@ -35,7 +35,6 @@
int
xfs_calc_dquots_per_chunk(
struct xfs_mount *mp,
unsigned int nbblks) /* basic block units */
{
unsigned int ndquots;
@ -194,7 +193,7 @@ xfs_dquot_buf_verify_crc(
if (mp->m_quotainfo)
ndquots = mp->m_quotainfo->qi_dqperchunk;
else
ndquots = xfs_calc_dquots_per_chunk(mp,
ndquots = xfs_calc_dquots_per_chunk(
XFS_BB_TO_FSB(mp, bp->b_length));
for (i = 0; i < ndquots; i++, d++) {
@ -225,7 +224,7 @@ xfs_dquot_buf_verify(
if (mp->m_quotainfo)
ndquots = mp->m_quotainfo->qi_dqperchunk;
else
ndquots = xfs_calc_dquots_per_chunk(mp, bp->b_length);
ndquots = xfs_calc_dquots_per_chunk(bp->b_length);
/*
* On the first read of the buffer, verify that each dquot is valid.

View file

@ -944,7 +944,7 @@ xfs_dir_open(
*/
mode = xfs_ilock_data_map_shared(ip);
if (ip->i_d.di_nextents > 0)
xfs_dir3_data_readahead(NULL, ip, 0, -1);
xfs_dir3_data_readahead(ip, 0, -1);
xfs_iunlock(ip, mode);
return 0;
}

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2006-2007 Silicon Graphics, Inc.
* Copyright (c) 2014 Christoph Hellwig.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@ -32,100 +33,20 @@
#include "xfs_filestream.h"
#include "xfs_trace.h"
#ifdef XFS_FILESTREAMS_TRACE
struct xfs_fstrm_item {
struct xfs_mru_cache_elem mru;
struct xfs_inode *ip;
xfs_agnumber_t ag; /* AG in use for this directory */
};
ktrace_t *xfs_filestreams_trace_buf;
STATIC void
xfs_filestreams_trace(
xfs_mount_t *mp, /* mount point */
int type, /* type of trace */
const char *func, /* source function */
int line, /* source line number */
__psunsigned_t arg0,
__psunsigned_t arg1,
__psunsigned_t arg2,
__psunsigned_t arg3,
__psunsigned_t arg4,
__psunsigned_t arg5)
{
ktrace_enter(xfs_filestreams_trace_buf,
(void *)(__psint_t)(type | (line << 16)),
(void *)func,
(void *)(__psunsigned_t)current_pid(),
(void *)mp,
(void *)(__psunsigned_t)arg0,
(void *)(__psunsigned_t)arg1,
(void *)(__psunsigned_t)arg2,
(void *)(__psunsigned_t)arg3,
(void *)(__psunsigned_t)arg4,
(void *)(__psunsigned_t)arg5,
NULL, NULL, NULL, NULL, NULL, NULL);
}
#define TRACE0(mp,t) TRACE6(mp,t,0,0,0,0,0,0)
#define TRACE1(mp,t,a0) TRACE6(mp,t,a0,0,0,0,0,0)
#define TRACE2(mp,t,a0,a1) TRACE6(mp,t,a0,a1,0,0,0,0)
#define TRACE3(mp,t,a0,a1,a2) TRACE6(mp,t,a0,a1,a2,0,0,0)
#define TRACE4(mp,t,a0,a1,a2,a3) TRACE6(mp,t,a0,a1,a2,a3,0,0)
#define TRACE5(mp,t,a0,a1,a2,a3,a4) TRACE6(mp,t,a0,a1,a2,a3,a4,0)
#define TRACE6(mp,t,a0,a1,a2,a3,a4,a5) \
xfs_filestreams_trace(mp, t, __func__, __LINE__, \
(__psunsigned_t)a0, (__psunsigned_t)a1, \
(__psunsigned_t)a2, (__psunsigned_t)a3, \
(__psunsigned_t)a4, (__psunsigned_t)a5)
#define TRACE_AG_SCAN(mp, ag, ag2) \
TRACE2(mp, XFS_FSTRM_KTRACE_AGSCAN, ag, ag2);
#define TRACE_AG_PICK1(mp, max_ag, maxfree) \
TRACE2(mp, XFS_FSTRM_KTRACE_AGPICK1, max_ag, maxfree);
#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) \
TRACE6(mp, XFS_FSTRM_KTRACE_AGPICK2, ag, ag2, \
cnt, free, scan, flag)
#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) \
TRACE5(mp, XFS_FSTRM_KTRACE_UPDATE, ip, ag, cnt, ag2, cnt2)
#define TRACE_FREE(mp, ip, pip, ag, cnt) \
TRACE4(mp, XFS_FSTRM_KTRACE_FREE, ip, pip, ag, cnt)
#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) \
TRACE4(mp, XFS_FSTRM_KTRACE_ITEM_LOOKUP, ip, pip, ag, cnt)
#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) \
TRACE4(mp, XFS_FSTRM_KTRACE_ASSOCIATE, ip, pip, ag, cnt)
#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) \
TRACE6(mp, XFS_FSTRM_KTRACE_MOVEAG, ip, pip, oag, ocnt, nag, ncnt)
#define TRACE_ORPHAN(mp, ip, ag) \
TRACE2(mp, XFS_FSTRM_KTRACE_ORPHAN, ip, ag);
#else
#define TRACE_AG_SCAN(mp, ag, ag2)
#define TRACE_AG_PICK1(mp, max_ag, maxfree)
#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag)
#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2)
#define TRACE_FREE(mp, ip, pip, ag, cnt)
#define TRACE_LOOKUP(mp, ip, pip, ag, cnt)
#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt)
#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt)
#define TRACE_ORPHAN(mp, ip, ag)
#endif
static kmem_zone_t *item_zone;
/*
* Structure for associating a file or a directory with an allocation group.
* The parent directory pointer is only needed for files, but since there will
* generally be vastly more files than directories in the cache, using the same
* data structure simplifies the code with very little memory overhead.
*/
typedef struct fstrm_item
{
xfs_agnumber_t ag; /* AG currently in use for the file/directory. */
xfs_inode_t *ip; /* inode self-pointer. */
xfs_inode_t *pip; /* Parent directory inode pointer. */
} fstrm_item_t;
enum xfs_fstrm_alloc {
XFS_PICK_USERDATA = 1,
XFS_PICK_LOWSPACE = 2,
};
/*
* Allocation group filestream associations are tracked with per-ag atomic
* counters. These counters allow _xfs_filestream_pick_ag() to tell whether a
* counters. These counters allow xfs_filestream_pick_ag() to tell whether a
* particular AG already has active filestreams associated with it. The mount
* point's m_peraglock is used to protect these counters from per-ag array
* re-allocation during a growfs operation. When xfs_growfs_data_private() is
@ -160,7 +81,7 @@ typedef struct fstrm_item
* the cache that reference per-ag array elements that have since been
* reallocated.
*/
static int
int
xfs_filestream_peek_ag(
xfs_mount_t *mp,
xfs_agnumber_t agno)
@ -200,23 +121,40 @@ xfs_filestream_put_ag(
xfs_perag_put(pag);
}
static void
xfs_fstrm_free_func(
struct xfs_mru_cache_elem *mru)
{
struct xfs_fstrm_item *item =
container_of(mru, struct xfs_fstrm_item, mru);
xfs_filestream_put_ag(item->ip->i_mount, item->ag);
trace_xfs_filestream_free(item->ip, item->ag);
kmem_free(item);
}
/*
* Scan the AGs starting at startag looking for an AG that isn't in use and has
* at least minlen blocks free.
*/
static int
_xfs_filestream_pick_ag(
xfs_mount_t *mp,
xfs_agnumber_t startag,
xfs_agnumber_t *agp,
int flags,
xfs_extlen_t minlen)
xfs_filestream_pick_ag(
struct xfs_inode *ip,
xfs_agnumber_t startag,
xfs_agnumber_t *agp,
int flags,
xfs_extlen_t minlen)
{
int streams, max_streams;
int err, trylock, nscan;
xfs_extlen_t longest, free, minfree, maxfree = 0;
xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
struct xfs_perag *pag;
struct xfs_mount *mp = ip->i_mount;
struct xfs_fstrm_item *item;
struct xfs_perag *pag;
xfs_extlen_t longest, free = 0, minfree, maxfree = 0;
xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
int err, trylock, nscan;
ASSERT(S_ISDIR(ip->i_d.di_mode));
/* 2% of an AG's blocks must be free for it to be chosen. */
minfree = mp->m_sb.sb_agblocks / 50;
@ -228,8 +166,9 @@ _xfs_filestream_pick_ag(
trylock = XFS_ALLOC_FLAG_TRYLOCK;
for (nscan = 0; 1; nscan++) {
trace_xfs_filestream_scan(ip, ag);
pag = xfs_perag_get(mp, ag);
TRACE_AG_SCAN(mp, ag, atomic_read(&pag->pagf_fstrms));
if (!pag->pagf_init) {
err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
@ -246,7 +185,6 @@ _xfs_filestream_pick_ag(
/* Keep track of the AG with the most free blocks. */
if (pag->pagf_freeblks > maxfree) {
maxfree = pag->pagf_freeblks;
max_streams = atomic_read(&pag->pagf_fstrms);
max_ag = ag;
}
@ -269,7 +207,6 @@ _xfs_filestream_pick_ag(
/* Break out, retaining the reference on the AG. */
free = pag->pagf_freeblks;
streams = atomic_read(&pag->pagf_fstrms);
xfs_perag_put(pag);
*agp = ag;
break;
@ -305,317 +242,98 @@ _xfs_filestream_pick_ag(
*/
if (max_ag != NULLAGNUMBER) {
xfs_filestream_get_ag(mp, max_ag);
TRACE_AG_PICK1(mp, max_ag, maxfree);
streams = max_streams;
free = maxfree;
*agp = max_ag;
break;
}
/* take AG 0 if none matched */
TRACE_AG_PICK1(mp, max_ag, maxfree);
trace_xfs_filestream_pick(ip, *agp, free, nscan);
*agp = 0;
return 0;
}
TRACE_AG_PICK2(mp, startag, *agp, streams, free, nscan, flags);
trace_xfs_filestream_pick(ip, *agp, free, nscan);
return 0;
}
/*
* Set the allocation group number for a file or a directory, updating inode
* references and per-AG references as appropriate.
*/
static int
_xfs_filestream_update_ag(
xfs_inode_t *ip,
xfs_inode_t *pip,
xfs_agnumber_t ag)
{
int err = 0;
xfs_mount_t *mp;
xfs_mru_cache_t *cache;
fstrm_item_t *item;
xfs_agnumber_t old_ag;
xfs_inode_t *old_pip;
/*
* Either ip is a regular file and pip is a directory, or ip is a
* directory and pip is NULL.
*/
ASSERT(ip && ((S_ISREG(ip->i_d.di_mode) && pip &&
S_ISDIR(pip->i_d.di_mode)) ||
(S_ISDIR(ip->i_d.di_mode) && !pip)));
mp = ip->i_mount;
cache = mp->m_filestream;
item = xfs_mru_cache_lookup(cache, ip->i_ino);
if (item) {
ASSERT(item->ip == ip);
old_ag = item->ag;
item->ag = ag;
old_pip = item->pip;
item->pip = pip;
xfs_mru_cache_done(cache);
/*
* If the AG has changed, drop the old ref and take a new one,
* effectively transferring the reference from old to new AG.
*/
if (ag != old_ag) {
xfs_filestream_put_ag(mp, old_ag);
xfs_filestream_get_ag(mp, ag);
}
/*
* If ip is a file and its pip has changed, drop the old ref and
* take a new one.
*/
if (pip && pip != old_pip) {
IRELE(old_pip);
IHOLD(pip);
}
TRACE_UPDATE(mp, ip, old_ag, xfs_filestream_peek_ag(mp, old_ag),
ag, xfs_filestream_peek_ag(mp, ag));
if (*agp == NULLAGNUMBER)
return 0;
}
item = kmem_zone_zalloc(item_zone, KM_MAYFAIL);
err = ENOMEM;
item = kmem_alloc(sizeof(*item), KM_MAYFAIL);
if (!item)
return ENOMEM;
goto out_put_ag;
item->ag = ag;
item->ag = *agp;
item->ip = ip;
item->pip = pip;
err = xfs_mru_cache_insert(cache, ip->i_ino, item);
err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru);
if (err) {
kmem_zone_free(item_zone, item);
return err;
if (err == EEXIST)
err = 0;
goto out_free_item;
}
/* Take a reference on the AG. */
xfs_filestream_get_ag(mp, ag);
/*
* Take a reference on the inode itself regardless of whether it's a
* regular file or a directory.
*/
IHOLD(ip);
/*
* In the case of a regular file, take a reference on the parent inode
* as well to ensure it remains in-core.
*/
if (pip)
IHOLD(pip);
TRACE_UPDATE(mp, ip, ag, xfs_filestream_peek_ag(mp, ag),
ag, xfs_filestream_peek_ag(mp, ag));
return 0;
}
/* xfs_fstrm_free_func(): callback for freeing cached stream items. */
STATIC void
xfs_fstrm_free_func(
unsigned long ino,
void *data)
{
fstrm_item_t *item = (fstrm_item_t *)data;
xfs_inode_t *ip = item->ip;
ASSERT(ip->i_ino == ino);
xfs_iflags_clear(ip, XFS_IFILESTREAM);
/* Drop the reference taken on the AG when the item was added. */
xfs_filestream_put_ag(ip->i_mount, item->ag);
TRACE_FREE(ip->i_mount, ip, item->pip, item->ag,
xfs_filestream_peek_ag(ip->i_mount, item->ag));
/*
* _xfs_filestream_update_ag() always takes a reference on the inode
* itself, whether it's a file or a directory. Release it here.
* This can result in the inode being freed and so we must
* not hold any inode locks when freeing filesstreams objects
* otherwise we can deadlock here.
*/
IRELE(ip);
/*
* In the case of a regular file, _xfs_filestream_update_ag() also
* takes a ref on the parent inode to keep it in-core. Release that
* too.
*/
if (item->pip)
IRELE(item->pip);
/* Finally, free the memory allocated for the item. */
kmem_zone_free(item_zone, item);
}
/*
* xfs_filestream_init() is called at xfs initialisation time to set up the
* memory zone that will be used for filestream data structure allocation.
*/
int
xfs_filestream_init(void)
{
item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item");
if (!item_zone)
return -ENOMEM;
return 0;
}
/*
* xfs_filestream_uninit() is called at xfs termination time to destroy the
* memory zone that was used for filestream data structure allocation.
*/
void
xfs_filestream_uninit(void)
{
kmem_zone_destroy(item_zone);
}
/*
* xfs_filestream_mount() is called when a file system is mounted with the
* filestream option. It is responsible for allocating the data structures
* needed to track the new file system's file streams.
*/
int
xfs_filestream_mount(
xfs_mount_t *mp)
{
int err;
unsigned int lifetime, grp_count;
/*
* The filestream timer tunable is currently fixed within the range of
* one second to four minutes, with five seconds being the default. The
* group count is somewhat arbitrary, but it'd be nice to adhere to the
* timer tunable to within about 10 percent. This requires at least 10
* groups.
*/
lifetime = xfs_fstrm_centisecs * 10;
grp_count = 10;
err = xfs_mru_cache_create(&mp->m_filestream, lifetime, grp_count,
xfs_fstrm_free_func);
out_free_item:
kmem_free(item);
out_put_ag:
xfs_filestream_put_ag(mp, *agp);
return err;
}
/*
* xfs_filestream_unmount() is called when a file system that was mounted with
* the filestream option is unmounted. It drains the data structures created
* to track the file system's file streams and frees all the memory that was
* allocated.
*/
void
xfs_filestream_unmount(
xfs_mount_t *mp)
static struct xfs_inode *
xfs_filestream_get_parent(
struct xfs_inode *ip)
{
xfs_mru_cache_destroy(mp->m_filestream);
struct inode *inode = VFS_I(ip), *dir = NULL;
struct dentry *dentry, *parent;
dentry = d_find_alias(inode);
if (!dentry)
goto out;
parent = dget_parent(dentry);
if (!parent)
goto out_dput;
dir = igrab(parent->d_inode);
dput(parent);
out_dput:
dput(dentry);
out:
return dir ? XFS_I(dir) : NULL;
}
/*
* Return the AG of the filestream the file or directory belongs to, or
* NULLAGNUMBER otherwise.
* Find the right allocation group for a file, either by finding an
* existing file stream or creating a new one.
*
* Returns NULLAGNUMBER in case of an error.
*/
xfs_agnumber_t
xfs_filestream_lookup_ag(
xfs_inode_t *ip)
struct xfs_inode *ip)
{
xfs_mru_cache_t *cache;
fstrm_item_t *item;
xfs_agnumber_t ag;
int ref;
struct xfs_mount *mp = ip->i_mount;
struct xfs_inode *pip = NULL;
xfs_agnumber_t startag, ag = NULLAGNUMBER;
struct xfs_mru_cache_elem *mru;
if (!S_ISREG(ip->i_d.di_mode) && !S_ISDIR(ip->i_d.di_mode)) {
ASSERT(0);
return NULLAGNUMBER;
}
cache = ip->i_mount->m_filestream;
item = xfs_mru_cache_lookup(cache, ip->i_ino);
if (!item) {
TRACE_LOOKUP(ip->i_mount, ip, NULL, NULLAGNUMBER, 0);
return NULLAGNUMBER;
}
ASSERT(ip == item->ip);
ag = item->ag;
ref = xfs_filestream_peek_ag(ip->i_mount, ag);
xfs_mru_cache_done(cache);
TRACE_LOOKUP(ip->i_mount, ip, item->pip, ag, ref);
return ag;
}
/*
* xfs_filestream_associate() should only be called to associate a regular file
* with its parent directory. Calling it with a child directory isn't
* appropriate because filestreams don't apply to entire directory hierarchies.
* Creating a file in a child directory of an existing filestream directory
* starts a new filestream with its own allocation group association.
*
* Returns < 0 on error, 0 if successful association occurred, > 0 if
* we failed to get an association because of locking issues.
*/
int
xfs_filestream_associate(
xfs_inode_t *pip,
xfs_inode_t *ip)
{
xfs_mount_t *mp;
xfs_mru_cache_t *cache;
fstrm_item_t *item;
xfs_agnumber_t ag, rotorstep, startag;
int err = 0;
ASSERT(S_ISDIR(pip->i_d.di_mode));
ASSERT(S_ISREG(ip->i_d.di_mode));
if (!S_ISDIR(pip->i_d.di_mode) || !S_ISREG(ip->i_d.di_mode))
return -EINVAL;
mp = pip->i_mount;
cache = mp->m_filestream;
pip = xfs_filestream_get_parent(ip);
if (!pip)
goto out;
/*
* We have a problem, Houston.
*
* Taking the iolock here violates inode locking order - we already
* hold the ilock. Hence if we block getting this lock we may never
* wake. Unfortunately, that means if we can't get the lock, we're
* screwed in terms of getting a stream association - we can't spin
* waiting for the lock because someone else is waiting on the lock we
* hold and we cannot drop that as we are in a transaction here.
*
* Lucky for us, this inversion is not a problem because it's a
* directory inode that we are trying to lock here.
*
* So, if we can't get the iolock without sleeping then just give up
*/
if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL))
return 1;
mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino);
if (mru) {
ag = container_of(mru, struct xfs_fstrm_item, mru)->ag;
xfs_mru_cache_done(mp->m_filestream);
/* If the parent directory is already in the cache, use its AG. */
item = xfs_mru_cache_lookup(cache, pip->i_ino);
if (item) {
ASSERT(item->ip == pip);
ag = item->ag;
xfs_mru_cache_done(cache);
TRACE_LOOKUP(mp, pip, pip, ag, xfs_filestream_peek_ag(mp, ag));
err = _xfs_filestream_update_ag(ip, pip, ag);
goto exit;
trace_xfs_filestream_lookup(ip, ag);
goto out;
}
/*
@ -623,202 +341,94 @@ xfs_filestream_associate(
* use the directory inode's AG.
*/
if (mp->m_flags & XFS_MOUNT_32BITINODES) {
rotorstep = xfs_rotorstep;
xfs_agnumber_t rotorstep = xfs_rotorstep;
startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
mp->m_agfrotor = (mp->m_agfrotor + 1) %
(mp->m_sb.sb_agcount * rotorstep);
} else
startag = XFS_INO_TO_AGNO(mp, pip->i_ino);
/* Pick a new AG for the parent inode starting at startag. */
err = _xfs_filestream_pick_ag(mp, startag, &ag, 0, 0);
if (err || ag == NULLAGNUMBER)
goto exit_did_pick;
/* Associate the parent inode with the AG. */
err = _xfs_filestream_update_ag(pip, NULL, ag);
if (err)
goto exit_did_pick;
/* Associate the file inode with the AG. */
err = _xfs_filestream_update_ag(ip, pip, ag);
if (err)
goto exit_did_pick;
TRACE_ASSOCIATE(mp, ip, pip, ag, xfs_filestream_peek_ag(mp, ag));
exit_did_pick:
/*
* If _xfs_filestream_pick_ag() returned a valid AG, remove the
* reference it took on it, since the file and directory will have taken
* their own now if they were successfully cached.
*/
if (ag != NULLAGNUMBER)
xfs_filestream_put_ag(mp, ag);
exit:
xfs_iunlock(pip, XFS_IOLOCK_EXCL);
return -err;
if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0))
ag = NULLAGNUMBER;
out:
IRELE(pip);
return ag;
}
/*
* Pick a new allocation group for the current file and its file stream. This
* function is called by xfs_bmap_filestreams() with the mount point's per-ag
* lock held.
* Pick a new allocation group for the current file and its file stream.
*
* This is called when the allocator can't find a suitable extent in the
* current AG, and we have to move the stream into a new AG with more space.
*/
int
xfs_filestream_new_ag(
struct xfs_bmalloca *ap,
xfs_agnumber_t *agp)
{
int flags, err;
xfs_inode_t *ip, *pip = NULL;
xfs_mount_t *mp;
xfs_mru_cache_t *cache;
xfs_extlen_t minlen;
fstrm_item_t *dir, *file;
xfs_agnumber_t ag = NULLAGNUMBER;
struct xfs_inode *ip = ap->ip, *pip;
struct xfs_mount *mp = ip->i_mount;
xfs_extlen_t minlen = ap->length;
xfs_agnumber_t startag = 0;
int flags, err = 0;
struct xfs_mru_cache_elem *mru;
ip = ap->ip;
mp = ip->i_mount;
cache = mp->m_filestream;
minlen = ap->length;
*agp = NULLAGNUMBER;
/*
* Look for the file in the cache, removing it if it's found. Doing
* this allows it to be held across the dir lookup that follows.
*/
file = xfs_mru_cache_remove(cache, ip->i_ino);
if (file) {
ASSERT(ip == file->ip);
pip = xfs_filestream_get_parent(ip);
if (!pip)
goto exit;
/* Save the file's parent inode and old AG number for later. */
pip = file->pip;
ag = file->ag;
/* Look for the file's directory in the cache. */
dir = xfs_mru_cache_lookup(cache, pip->i_ino);
if (dir) {
ASSERT(pip == dir->ip);
/*
* If the directory has already moved on to a new AG,
* use that AG as the new AG for the file. Don't
* forget to twiddle the AG refcounts to match the
* movement.
*/
if (dir->ag != file->ag) {
xfs_filestream_put_ag(mp, file->ag);
xfs_filestream_get_ag(mp, dir->ag);
*agp = file->ag = dir->ag;
}
xfs_mru_cache_done(cache);
}
/*
* Put the file back in the cache. If this fails, the free
* function needs to be called to tidy up in the same way as if
* the item had simply expired from the cache.
*/
err = xfs_mru_cache_insert(cache, ip->i_ino, file);
if (err) {
xfs_fstrm_free_func(ip->i_ino, file);
return err;
}
/*
* If the file's AG was moved to the directory's new AG, there's
* nothing more to be done.
*/
if (*agp != NULLAGNUMBER) {
TRACE_MOVEAG(mp, ip, pip,
ag, xfs_filestream_peek_ag(mp, ag),
*agp, xfs_filestream_peek_ag(mp, *agp));
return 0;
}
mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino);
if (mru) {
struct xfs_fstrm_item *item =
container_of(mru, struct xfs_fstrm_item, mru);
startag = (item->ag + 1) % mp->m_sb.sb_agcount;
}
/*
* If the file's parent directory is known, take its iolock in exclusive
* mode to prevent two sibling files from racing each other to migrate
* themselves and their parent to different AGs.
*
* Note that we lock the parent directory iolock inside the child
* iolock here. That's fine as we never hold both parent and child
* iolock in any other place. This is different from the ilock,
* which requires locking of the child after the parent for namespace
* operations.
*/
if (pip)
xfs_ilock(pip, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT);
/*
* A new AG needs to be found for the file. If the file's parent
* directory is also known, it will be moved to the new AG as well to
* ensure that files created inside it in future use the new AG.
*/
ag = (ag == NULLAGNUMBER) ? 0 : (ag + 1) % mp->m_sb.sb_agcount;
flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
(ap->flist->xbf_low ? XFS_PICK_LOWSPACE : 0);
err = _xfs_filestream_pick_ag(mp, ag, agp, flags, minlen);
if (err || *agp == NULLAGNUMBER)
goto exit;
err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen);
/*
* If the file wasn't found in the file cache, then its parent directory
* inode isn't known. For this to have happened, the file must either
* be pre-existing, or it was created long enough ago that its cache
* entry has expired. This isn't the sort of usage that the filestreams
* allocator is trying to optimise, so there's no point trying to track
* its new AG somehow in the filestream data structures.
* Only free the item here so we skip over the old AG earlier.
*/
if (!pip) {
TRACE_ORPHAN(mp, ip, *agp);
goto exit;
}
/* Associate the parent inode with the AG. */
err = _xfs_filestream_update_ag(pip, NULL, *agp);
if (err)
goto exit;
/* Associate the file inode with the AG. */
err = _xfs_filestream_update_ag(ip, pip, *agp);
if (err)
goto exit;
TRACE_MOVEAG(mp, ip, pip, NULLAGNUMBER, 0,
*agp, xfs_filestream_peek_ag(mp, *agp));
if (mru)
xfs_fstrm_free_func(mru);
IRELE(pip);
exit:
/*
* If _xfs_filestream_pick_ag() returned a valid AG, remove the
* reference it took on it, since the file and directory will have taken
* their own now if they were successfully cached.
*/
if (*agp != NULLAGNUMBER)
xfs_filestream_put_ag(mp, *agp);
else
if (*agp == NULLAGNUMBER)
*agp = 0;
if (pip)
xfs_iunlock(pip, XFS_IOLOCK_EXCL);
return err;
}
/*
* Remove an association between an inode and a filestream object.
* Typically this is done on last close of an unlinked file.
*/
void
xfs_filestream_deassociate(
xfs_inode_t *ip)
struct xfs_inode *ip)
{
xfs_mru_cache_t *cache = ip->i_mount->m_filestream;
xfs_mru_cache_delete(cache, ip->i_ino);
xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino);
}
int
xfs_filestream_mount(
xfs_mount_t *mp)
{
/*
* The filestream timer tunable is currently fixed within the range of
* one second to four minutes, with five seconds being the default. The
* group count is somewhat arbitrary, but it'd be nice to adhere to the
* timer tunable to within about 10 percent. This requires at least 10
* groups.
*/
return xfs_mru_cache_create(&mp->m_filestream, xfs_fstrm_centisecs * 10,
10, xfs_fstrm_free_func);
}
void
xfs_filestream_unmount(
xfs_mount_t *mp)
{
xfs_mru_cache_destroy(mp->m_filestream);
}

View file

@ -20,50 +20,20 @@
struct xfs_mount;
struct xfs_inode;
struct xfs_perag;
struct xfs_bmalloca;
#ifdef XFS_FILESTREAMS_TRACE
#define XFS_FSTRM_KTRACE_INFO 1
#define XFS_FSTRM_KTRACE_AGSCAN 2
#define XFS_FSTRM_KTRACE_AGPICK1 3
#define XFS_FSTRM_KTRACE_AGPICK2 4
#define XFS_FSTRM_KTRACE_UPDATE 5
#define XFS_FSTRM_KTRACE_FREE 6
#define XFS_FSTRM_KTRACE_ITEM_LOOKUP 7
#define XFS_FSTRM_KTRACE_ASSOCIATE 8
#define XFS_FSTRM_KTRACE_MOVEAG 9
#define XFS_FSTRM_KTRACE_ORPHAN 10
#define XFS_FSTRM_KTRACE_SIZE 16384
extern ktrace_t *xfs_filestreams_trace_buf;
#endif
/* allocation selection flags */
typedef enum xfs_fstrm_alloc {
XFS_PICK_USERDATA = 1,
XFS_PICK_LOWSPACE = 2,
} xfs_fstrm_alloc_t;
/* prototypes for filestream.c */
int xfs_filestream_init(void);
void xfs_filestream_uninit(void);
int xfs_filestream_mount(struct xfs_mount *mp);
void xfs_filestream_unmount(struct xfs_mount *mp);
xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip);
void xfs_filestream_deassociate(struct xfs_inode *ip);
xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
int xfs_filestream_new_ag(struct xfs_bmalloca *ap, xfs_agnumber_t *agp);
int xfs_filestream_peek_ag(struct xfs_mount *mp, xfs_agnumber_t agno);
/* filestreams for the inode? */
static inline int
xfs_inode_is_filestream(
struct xfs_inode *ip)
{
return (ip->i_mount->m_flags & XFS_MOUNT_FILESTREAMS) ||
xfs_iflags_test(ip, XFS_IFILESTREAM) ||
(ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM);
}

View file

@ -202,6 +202,8 @@ typedef __be32 xfs_alloc_ptr_t;
*/
#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */
#define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */
#define XFS_FIBT_MAGIC 0x46494254 /* 'FIBT' */
#define XFS_FIBT_CRC_MAGIC 0x46494233 /* 'FIB3' */
typedef __uint64_t xfs_inofree_t;
#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t))
@ -244,7 +246,17 @@ typedef __be32 xfs_inobt_ptr_t;
* block numbers in the AG.
*/
#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1))
#define XFS_PREALLOC_BLOCKS(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
#define XFS_FIBT_BLOCK(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1))
/*
* The first data block of an AG depends on whether the filesystem was formatted
* with the finobt feature. If so, account for the finobt reserved root btree
* block.
*/
#define XFS_PREALLOC_BLOCKS(mp) \
(xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \
XFS_FIBT_BLOCK(mp) + 1 : \
XFS_IBT_BLOCK(mp) + 1)

View file

@ -238,6 +238,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */
#define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */
#define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */
/*
* Minimum and maximum sizes need for growth checks.

View file

@ -24,6 +24,8 @@
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_inode.h"
#include "xfs_trans.h"
#include "xfs_inode_item.h"
@ -74,23 +76,18 @@ xfs_fs_geometry(
}
if (new_version >= 3) {
geo->version = XFS_FSOP_GEOM_VERSION;
geo->flags =
geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK |
XFS_FSOP_GEOM_FLAGS_DIRV2 |
(xfs_sb_version_hasattr(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_ATTR : 0) |
(xfs_sb_version_hasnlink(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_NLINK : 0) |
(xfs_sb_version_hasquota(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_QUOTA : 0) |
(xfs_sb_version_hasalign(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_IALIGN : 0) |
(xfs_sb_version_hasdalign(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_DALIGN : 0) |
(xfs_sb_version_hasshared(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_SHARED : 0) |
(xfs_sb_version_hasextflgbit(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) |
(xfs_sb_version_hasdirv2(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
(xfs_sb_version_hassector(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
(xfs_sb_version_hasasciici(&mp->m_sb) ?
@ -104,11 +101,13 @@ xfs_fs_geometry(
(xfs_sb_version_hascrc(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_V5SB : 0) |
(xfs_sb_version_hasftype(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_FTYPE : 0);
XFS_FSOP_GEOM_FLAGS_FTYPE : 0) |
(xfs_sb_version_hasfinobt(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_FINOBT : 0);
geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ?
mp->m_sb.sb_logsectsize : BBSIZE;
geo->rtsectsize = mp->m_sb.sb_blocksize;
geo->dirblocksize = mp->m_dirblksize;
geo->dirblocksize = mp->m_dir_geo->blksize;
}
if (new_version >= 4) {
geo->flags |=
@ -316,6 +315,10 @@ xfs_growfs_data_private(
agi->agi_dirino = cpu_to_be32(NULLAGINO);
if (xfs_sb_version_hascrc(&mp->m_sb))
uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_uuid);
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
agi->agi_free_level = cpu_to_be32(1);
}
for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
@ -407,6 +410,34 @@ xfs_growfs_data_private(
xfs_buf_relse(bp);
if (error)
goto error0;
/*
* FINO btree root block
*/
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
bp = xfs_growfs_get_hdr_buf(mp,
XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)),
BTOBB(mp->m_sb.sb_blocksize), 0,
&xfs_inobt_buf_ops);
if (!bp) {
error = ENOMEM;
goto error0;
}
if (xfs_sb_version_hascrc(&mp->m_sb))
xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC,
0, 0, agno,
XFS_BTREE_CRC_BLOCKS);
else
xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0,
0, agno, 0);
error = xfs_bwrite(bp);
xfs_buf_relse(bp);
if (error)
goto error0;
}
}
xfs_trans_agblocks_delta(tp, nfree);
/*

View file

@ -111,6 +111,66 @@ xfs_inobt_get_rec(
return error;
}
/*
* Insert a single inobt record. Cursor must already point to desired location.
*/
STATIC int
xfs_inobt_insert_rec(
struct xfs_btree_cur *cur,
__int32_t freecount,
xfs_inofree_t free,
int *stat)
{
cur->bc_rec.i.ir_freecount = freecount;
cur->bc_rec.i.ir_free = free;
return xfs_btree_insert(cur, stat);
}
/*
* Insert records describing a newly allocated inode chunk into the inobt.
*/
STATIC int
xfs_inobt_insert(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_agino_t newino,
xfs_agino_t newlen,
xfs_btnum_t btnum)
{
struct xfs_btree_cur *cur;
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
xfs_agino_t thisino;
int i;
int error;
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum);
for (thisino = newino;
thisino < newino + newlen;
thisino += XFS_INODES_PER_CHUNK) {
error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i);
if (error) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
ASSERT(i == 0);
error = xfs_inobt_insert_rec(cur, XFS_INODES_PER_CHUNK,
XFS_INOBT_ALL_FREE, &i);
if (error) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
ASSERT(i == 1);
}
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
return 0;
}
/*
* Verify that the number of free inodes in the AGI is correct.
*/
@ -220,10 +280,8 @@ xfs_ialloc_inode_init(
if (tp)
xfs_icreate_log(tp, agno, agbno, mp->m_ialloc_inos,
mp->m_sb.sb_inodesize, length, gen);
} else if (xfs_sb_version_hasnlink(&mp->m_sb))
} else
version = 2;
else
version = 1;
for (j = 0; j < nbufs; j++) {
/*
@ -303,13 +361,10 @@ xfs_ialloc_ag_alloc(
{
xfs_agi_t *agi; /* allocation group header */
xfs_alloc_arg_t args; /* allocation argument structure */
xfs_btree_cur_t *cur; /* inode btree cursor */
xfs_agnumber_t agno;
int error;
int i;
xfs_agino_t newino; /* new first inode's number */
xfs_agino_t newlen; /* new number of inodes */
xfs_agino_t thisino; /* current inode number, for loop */
int isaligned = 0; /* inode allocation at stripe unit */
/* boundary */
struct xfs_perag *pag;
@ -459,29 +514,19 @@ xfs_ialloc_ag_alloc(
agi->agi_newino = cpu_to_be32(newino);
/*
* Insert records describing the new inode chunk into the btree.
* Insert records describing the new inode chunk into the btrees.
*/
cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno);
for (thisino = newino;
thisino < newino + newlen;
thisino += XFS_INODES_PER_CHUNK) {
cur->bc_rec.i.ir_startino = thisino;
cur->bc_rec.i.ir_freecount = XFS_INODES_PER_CHUNK;
cur->bc_rec.i.ir_free = XFS_INOBT_ALL_FREE;
error = xfs_btree_lookup(cur, XFS_LOOKUP_EQ, &i);
if (error) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
XFS_BTNUM_INO);
if (error)
return error;
if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) {
error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen,
XFS_BTNUM_FINO);
if (error)
return error;
}
ASSERT(i == 0);
error = xfs_btree_insert(cur, &i);
if (error) {
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
ASSERT(i == 1);
}
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
/*
* Log allocation group header fields
*/
@ -675,13 +720,10 @@ xfs_ialloc_get_rec(
}
/*
* Allocate an inode.
*
* The caller selected an AG for us, and made sure that free inodes are
* available.
* Allocate an inode using the inobt-only algorithm.
*/
STATIC int
xfs_dialloc_ag(
xfs_dialloc_ag_inobt(
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_ino_t parent,
@ -707,7 +749,7 @@ xfs_dialloc_ag(
ASSERT(pag->pagi_freecount > 0);
restart_pagno:
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
/*
* If pagino is 0 (this is the root inode allocation) use newino.
* This must work because we've just allocated some.
@ -939,6 +981,294 @@ xfs_dialloc_ag(
return error;
}
/*
* Use the free inode btree to allocate an inode based on distance from the
* parent. Note that the provided cursor may be deleted and replaced.
*/
STATIC int
xfs_dialloc_ag_finobt_near(
xfs_agino_t pagino,
struct xfs_btree_cur **ocur,
struct xfs_inobt_rec_incore *rec)
{
struct xfs_btree_cur *lcur = *ocur; /* left search cursor */
struct xfs_btree_cur *rcur; /* right search cursor */
struct xfs_inobt_rec_incore rrec;
int error;
int i, j;
error = xfs_inobt_lookup(lcur, pagino, XFS_LOOKUP_LE, &i);
if (error)
return error;
if (i == 1) {
error = xfs_inobt_get_rec(lcur, rec, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
/*
* See if we've landed in the parent inode record. The finobt
* only tracks chunks with at least one free inode, so record
* existence is enough.
*/
if (pagino >= rec->ir_startino &&
pagino < (rec->ir_startino + XFS_INODES_PER_CHUNK))
return 0;
}
error = xfs_btree_dup_cursor(lcur, &rcur);
if (error)
return error;
error = xfs_inobt_lookup(rcur, pagino, XFS_LOOKUP_GE, &j);
if (error)
goto error_rcur;
if (j == 1) {
error = xfs_inobt_get_rec(rcur, &rrec, &j);
if (error)
goto error_rcur;
XFS_WANT_CORRUPTED_GOTO(j == 1, error_rcur);
}
XFS_WANT_CORRUPTED_GOTO(i == 1 || j == 1, error_rcur);
if (i == 1 && j == 1) {
/*
* Both the left and right records are valid. Choose the closer
* inode chunk to the target.
*/
if ((pagino - rec->ir_startino + XFS_INODES_PER_CHUNK - 1) >
(rrec.ir_startino - pagino)) {
*rec = rrec;
xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR);
*ocur = rcur;
} else {
xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR);
}
} else if (j == 1) {
/* only the right record is valid */
*rec = rrec;
xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR);
*ocur = rcur;
} else if (i == 1) {
/* only the left record is valid */
xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR);
}
return 0;
error_rcur:
xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR);
return error;
}
/*
* Use the free inode btree to find a free inode based on a newino hint. If
* the hint is NULL, find the first free inode in the AG.
*/
STATIC int
xfs_dialloc_ag_finobt_newino(
struct xfs_agi *agi,
struct xfs_btree_cur *cur,
struct xfs_inobt_rec_incore *rec)
{
int error;
int i;
if (agi->agi_newino != cpu_to_be32(NULLAGINO)) {
error = xfs_inobt_lookup(cur, agi->agi_newino, XFS_LOOKUP_EQ,
&i);
if (error)
return error;
if (i == 1) {
error = xfs_inobt_get_rec(cur, rec, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
return 0;
}
}
/*
* Find the first inode available in the AG.
*/
error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
error = xfs_inobt_get_rec(cur, rec, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
return 0;
}
/*
* Update the inobt based on a modification made to the finobt. Also ensure that
* the records from both trees are equivalent post-modification.
*/
STATIC int
xfs_dialloc_ag_update_inobt(
struct xfs_btree_cur *cur, /* inobt cursor */
struct xfs_inobt_rec_incore *frec, /* finobt record */
int offset) /* inode offset */
{
struct xfs_inobt_rec_incore rec;
int error;
int i;
error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
error = xfs_inobt_get_rec(cur, &rec, &i);
if (error)
return error;
XFS_WANT_CORRUPTED_RETURN(i == 1);
ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) %
XFS_INODES_PER_CHUNK) == 0);
rec.ir_free &= ~XFS_INOBT_MASK(offset);
rec.ir_freecount--;
XFS_WANT_CORRUPTED_RETURN((rec.ir_free == frec->ir_free) &&
(rec.ir_freecount == frec->ir_freecount));
error = xfs_inobt_update(cur, &rec);
if (error)
return error;
return 0;
}
/*
* Allocate an inode using the free inode btree, if available. Otherwise, fall
* back to the inobt search algorithm.
*
* The caller selected an AG for us, and made sure that free inodes are
* available.
*/
STATIC int
xfs_dialloc_ag(
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_ino_t parent,
xfs_ino_t *inop)
{
struct xfs_mount *mp = tp->t_mountp;
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent);
xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent);
struct xfs_perag *pag;
struct xfs_btree_cur *cur; /* finobt cursor */
struct xfs_btree_cur *icur; /* inobt cursor */
struct xfs_inobt_rec_incore rec;
xfs_ino_t ino;
int error;
int offset;
int i;
if (!xfs_sb_version_hasfinobt(&mp->m_sb))
return xfs_dialloc_ag_inobt(tp, agbp, parent, inop);
pag = xfs_perag_get(mp, agno);
/*
* If pagino is 0 (this is the root inode allocation) use newino.
* This must work because we've just allocated some.
*/
if (!pagino)
pagino = be32_to_cpu(agi->agi_newino);
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
error = xfs_check_agi_freecount(cur, agi);
if (error)
goto error_cur;
/*
* The search algorithm depends on whether we're in the same AG as the
* parent. If so, find the closest available inode to the parent. If
* not, consider the agi hint or find the first free inode in the AG.
*/
if (agno == pagno)
error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec);
else
error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec);
if (error)
goto error_cur;
offset = xfs_lowbit64(rec.ir_free);
ASSERT(offset >= 0);
ASSERT(offset < XFS_INODES_PER_CHUNK);
ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) %
XFS_INODES_PER_CHUNK) == 0);
ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset);
/*
* Modify or remove the finobt record.
*/
rec.ir_free &= ~XFS_INOBT_MASK(offset);
rec.ir_freecount--;
if (rec.ir_freecount)
error = xfs_inobt_update(cur, &rec);
else
error = xfs_btree_delete(cur, &i);
if (error)
goto error_cur;
/*
* The finobt has now been updated appropriately. We haven't updated the
* agi and superblock yet, so we can create an inobt cursor and validate
* the original freecount. If all is well, make the equivalent update to
* the inobt using the finobt record and offset information.
*/
icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
error = xfs_check_agi_freecount(icur, agi);
if (error)
goto error_icur;
error = xfs_dialloc_ag_update_inobt(icur, &rec, offset);
if (error)
goto error_icur;
/*
* Both trees have now been updated. We must update the perag and
* superblock before we can check the freecount for each btree.
*/
be32_add_cpu(&agi->agi_freecount, -1);
xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT);
pag->pagi_freecount--;
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1);
error = xfs_check_agi_freecount(icur, agi);
if (error)
goto error_icur;
error = xfs_check_agi_freecount(cur, agi);
if (error)
goto error_icur;
xfs_btree_del_cursor(icur, XFS_BTREE_NOERROR);
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
xfs_perag_put(pag);
*inop = ino;
return 0;
error_icur:
xfs_btree_del_cursor(icur, XFS_BTREE_ERROR);
error_cur:
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
xfs_perag_put(pag);
return error;
}
/*
* Allocate an inode on disk.
*
@ -1098,78 +1428,34 @@ xfs_dialloc(
return XFS_ERROR(error);
}
/*
* Free disk inode. Carefully avoids touching the incore inode, all
* manipulations incore are the caller's responsibility.
* The on-disk inode is not changed by this operation, only the
* btree (free inode mask) is changed.
*/
int
xfs_difree(
xfs_trans_t *tp, /* transaction pointer */
xfs_ino_t inode, /* inode to be freed */
xfs_bmap_free_t *flist, /* extents to free */
int *delete, /* set if inode cluster was deleted */
xfs_ino_t *first_ino) /* first inode in deleted cluster */
STATIC int
xfs_difree_inobt(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_agino_t agino,
struct xfs_bmap_free *flist,
int *deleted,
xfs_ino_t *first_ino,
struct xfs_inobt_rec_incore *orec)
{
/* REFERENCED */
xfs_agblock_t agbno; /* block number containing inode */
xfs_buf_t *agbp; /* buffer containing allocation group header */
xfs_agino_t agino; /* inode number relative to allocation group */
xfs_agnumber_t agno; /* allocation group number */
xfs_agi_t *agi; /* allocation group header */
xfs_btree_cur_t *cur; /* inode btree cursor */
int error; /* error return value */
int i; /* result code */
int ilen; /* inodes in an inode cluster */
xfs_mount_t *mp; /* mount structure for filesystem */
int off; /* offset of inode in inode chunk */
xfs_inobt_rec_incore_t rec; /* btree record */
struct xfs_perag *pag;
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
struct xfs_perag *pag;
struct xfs_btree_cur *cur;
struct xfs_inobt_rec_incore rec;
int ilen;
int error;
int i;
int off;
mp = tp->t_mountp;
/*
* Break up inode number into its components.
*/
agno = XFS_INO_TO_AGNO(mp, inode);
if (agno >= mp->m_sb.sb_agcount) {
xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
__func__, agno, mp->m_sb.sb_agcount);
ASSERT(0);
return XFS_ERROR(EINVAL);
}
agino = XFS_INO_TO_AGINO(mp, inode);
if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) {
xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
__func__, (unsigned long long)inode,
(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
ASSERT(0);
return XFS_ERROR(EINVAL);
}
agbno = XFS_AGINO_TO_AGBNO(mp, agino);
if (agbno >= mp->m_sb.sb_agblocks) {
xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
__func__, agbno, mp->m_sb.sb_agblocks);
ASSERT(0);
return XFS_ERROR(EINVAL);
}
/*
* Get the allocation group header.
*/
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
if (error) {
xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
__func__, error);
return error;
}
agi = XFS_BUF_TO_AGI(agbp);
ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
ASSERT(agbno < be32_to_cpu(agi->agi_length));
ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length));
/*
* Initialize the cursor.
*/
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
error = xfs_check_agi_freecount(cur, agi);
if (error)
@ -1209,7 +1495,7 @@ xfs_difree(
if (!(mp->m_flags & XFS_MOUNT_IKEEP) &&
(rec.ir_freecount == mp->m_ialloc_inos)) {
*delete = 1;
*deleted = 1;
*first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino);
/*
@ -1237,7 +1523,7 @@ xfs_difree(
XFS_AGINO_TO_AGBNO(mp, rec.ir_startino)),
mp->m_ialloc_blks, flist, mp);
} else {
*delete = 0;
*deleted = 0;
error = xfs_inobt_update(cur, &rec);
if (error) {
@ -1261,6 +1547,7 @@ xfs_difree(
if (error)
goto error0;
*orec = rec;
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
return 0;
@ -1269,6 +1556,182 @@ xfs_difree(
return error;
}
/*
* Free an inode in the free inode btree.
*/
STATIC int
xfs_difree_finobt(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_agino_t agino,
struct xfs_inobt_rec_incore *ibtrec) /* inobt record */
{
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
struct xfs_btree_cur *cur;
struct xfs_inobt_rec_incore rec;
int offset = agino - ibtrec->ir_startino;
int error;
int i;
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
if (error)
goto error;
if (i == 0) {
/*
* If the record does not exist in the finobt, we must have just
* freed an inode in a previously fully allocated chunk. If not,
* something is out of sync.
*/
XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error);
error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount,
ibtrec->ir_free, &i);
if (error)
goto error;
ASSERT(i == 1);
goto out;
}
/*
* Read and update the existing record. We could just copy the ibtrec
* across here, but that would defeat the purpose of having redundant
* metadata. By making the modifications independently, we can catch
* corruptions that we wouldn't see if we just copied from one record
* to another.
*/
error = xfs_inobt_get_rec(cur, &rec, &i);
if (error)
goto error;
XFS_WANT_CORRUPTED_GOTO(i == 1, error);
rec.ir_free |= XFS_INOBT_MASK(offset);
rec.ir_freecount++;
XFS_WANT_CORRUPTED_GOTO((rec.ir_free == ibtrec->ir_free) &&
(rec.ir_freecount == ibtrec->ir_freecount),
error);
/*
* The content of inobt records should always match between the inobt
* and finobt. The lifecycle of records in the finobt is different from
* the inobt in that the finobt only tracks records with at least one
* free inode. Hence, if all of the inodes are free and we aren't
* keeping inode chunks permanently on disk, remove the record.
* Otherwise, update the record with the new information.
*/
if (rec.ir_freecount == mp->m_ialloc_inos &&
!(mp->m_flags & XFS_MOUNT_IKEEP)) {
error = xfs_btree_delete(cur, &i);
if (error)
goto error;
ASSERT(i == 1);
} else {
error = xfs_inobt_update(cur, &rec);
if (error)
goto error;
}
out:
error = xfs_check_agi_freecount(cur, agi);
if (error)
goto error;
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
return 0;
error:
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
/*
* Free disk inode. Carefully avoids touching the incore inode, all
* manipulations incore are the caller's responsibility.
* The on-disk inode is not changed by this operation, only the
* btree (free inode mask) is changed.
*/
int
xfs_difree(
struct xfs_trans *tp, /* transaction pointer */
xfs_ino_t inode, /* inode to be freed */
struct xfs_bmap_free *flist, /* extents to free */
int *deleted,/* set if inode cluster was deleted */
xfs_ino_t *first_ino)/* first inode in deleted cluster */
{
/* REFERENCED */
xfs_agblock_t agbno; /* block number containing inode */
struct xfs_buf *agbp; /* buffer for allocation group header */
xfs_agino_t agino; /* allocation group inode number */
xfs_agnumber_t agno; /* allocation group number */
int error; /* error return value */
struct xfs_mount *mp; /* mount structure for filesystem */
struct xfs_inobt_rec_incore rec;/* btree record */
mp = tp->t_mountp;
/*
* Break up inode number into its components.
*/
agno = XFS_INO_TO_AGNO(mp, inode);
if (agno >= mp->m_sb.sb_agcount) {
xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).",
__func__, agno, mp->m_sb.sb_agcount);
ASSERT(0);
return XFS_ERROR(EINVAL);
}
agino = XFS_INO_TO_AGINO(mp, inode);
if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) {
xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).",
__func__, (unsigned long long)inode,
(unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino));
ASSERT(0);
return XFS_ERROR(EINVAL);
}
agbno = XFS_AGINO_TO_AGBNO(mp, agino);
if (agbno >= mp->m_sb.sb_agblocks) {
xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).",
__func__, agbno, mp->m_sb.sb_agblocks);
ASSERT(0);
return XFS_ERROR(EINVAL);
}
/*
* Get the allocation group header.
*/
error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
if (error) {
xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.",
__func__, error);
return error;
}
/*
* Fix up the inode allocation btree.
*/
error = xfs_difree_inobt(mp, tp, agbp, agino, flist, deleted, first_ino,
&rec);
if (error)
goto error0;
/*
* Fix up the free inode btree.
*/
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
if (error)
goto error0;
}
return 0;
error0:
return error;
}
STATIC int
xfs_imap_lookup(
struct xfs_mount *mp,
@ -1300,7 +1763,7 @@ xfs_imap_lookup(
* we have a record, we need to ensure it contains the inode number
* we are looking up.
*/
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO);
error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i);
if (!error) {
if (i)
@ -1488,7 +1951,16 @@ xfs_ialloc_compute_maxlevels(
}
/*
* Log specified fields for the ag hdr (inode section)
* Log specified fields for the ag hdr (inode section). The growth of the agi
* structure over time requires that we interpret the buffer as two logical
* regions delineated by the end of the unlinked list. This is due to the size
* of the hash table and its location in the middle of the agi.
*
* For example, a request to log a field before agi_unlinked and a field after
* agi_unlinked could cause us to log the entire hash table and use an excessive
* amount of log space. To avoid this behavior, log the region up through
* agi_unlinked in one call and the region after agi_unlinked through the end of
* the structure in another.
*/
void
xfs_ialloc_log_agi(
@ -1511,6 +1983,8 @@ xfs_ialloc_log_agi(
offsetof(xfs_agi_t, agi_newino),
offsetof(xfs_agi_t, agi_dirino),
offsetof(xfs_agi_t, agi_unlinked),
offsetof(xfs_agi_t, agi_free_root),
offsetof(xfs_agi_t, agi_free_level),
sizeof(xfs_agi_t)
};
#ifdef DEBUG
@ -1519,15 +1993,30 @@ xfs_ialloc_log_agi(
agi = XFS_BUF_TO_AGI(bp);
ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC));
#endif
/*
* Compute byte offsets for the first and last fields.
*/
xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS, &first, &last);
/*
* Log the allocation group inode header buffer.
*/
xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF);
xfs_trans_log_buf(tp, bp, first, last);
/*
* Compute byte offsets for the first and last fields in the first
* region and log the agi buffer. This only logs up through
* agi_unlinked.
*/
if (fields & XFS_AGI_ALL_BITS_R1) {
xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1,
&first, &last);
xfs_trans_log_buf(tp, bp, first, last);
}
/*
* Mask off the bits in the first region and calculate the first and
* last field offsets for any bits in the second region.
*/
fields &= ~XFS_AGI_ALL_BITS_R1;
if (fields) {
xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2,
&first, &last);
xfs_trans_log_buf(tp, bp, first, last);
}
}
#ifdef DEBUG
@ -1640,7 +2129,6 @@ xfs_read_agi(
if (error)
return error;
ASSERT(!xfs_buf_geterror(*bpp));
xfs_buf_set_ref(*bpp, XFS_AGI_REF);
return 0;
}

View file

@ -90,7 +90,7 @@ xfs_difree(
struct xfs_trans *tp, /* transaction pointer */
xfs_ino_t inode, /* inode to be freed */
struct xfs_bmap_free *flist, /* extents to free */
int *delete, /* set if inode cluster was deleted */
int *deleted, /* set if inode cluster was deleted */
xfs_ino_t *first_ino); /* first inode in deleted cluster */
/*

View file

@ -49,7 +49,8 @@ xfs_inobt_dup_cursor(
struct xfs_btree_cur *cur)
{
return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
cur->bc_private.a.agbp, cur->bc_private.a.agno);
cur->bc_private.a.agbp, cur->bc_private.a.agno,
cur->bc_btnum);
}
STATIC void
@ -66,12 +67,26 @@ xfs_inobt_set_root(
xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL);
}
STATIC void
xfs_finobt_set_root(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *nptr,
int inc) /* level change */
{
struct xfs_buf *agbp = cur->bc_private.a.agbp;
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
agi->agi_free_root = nptr->s;
be32_add_cpu(&agi->agi_free_level, inc);
xfs_ialloc_log_agi(cur->bc_tp, agbp,
XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL);
}
STATIC int
xfs_inobt_alloc_block(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *start,
union xfs_btree_ptr *new,
int length,
int *stat)
{
xfs_alloc_arg_t args; /* block allocation args */
@ -173,6 +188,17 @@ xfs_inobt_init_ptr_from_cur(
ptr->s = agi->agi_root;
}
STATIC void
xfs_finobt_init_ptr_from_cur(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *ptr)
{
struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
ptr->s = agi->agi_free_root;
}
STATIC __int64_t
xfs_inobt_key_diff(
struct xfs_btree_cur *cur,
@ -203,6 +229,7 @@ xfs_inobt_verify(
*/
switch (block->bb_magic) {
case cpu_to_be32(XFS_IBT_CRC_MAGIC):
case cpu_to_be32(XFS_FIBT_CRC_MAGIC):
if (!xfs_sb_version_hascrc(&mp->m_sb))
return false;
if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid))
@ -214,6 +241,7 @@ xfs_inobt_verify(
return false;
/* fall through */
case cpu_to_be32(XFS_IBT_MAGIC):
case cpu_to_be32(XFS_FIBT_MAGIC):
break;
default:
return 0;
@ -317,6 +345,28 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
#endif
};
static const struct xfs_btree_ops xfs_finobt_ops = {
.rec_len = sizeof(xfs_inobt_rec_t),
.key_len = sizeof(xfs_inobt_key_t),
.dup_cursor = xfs_inobt_dup_cursor,
.set_root = xfs_finobt_set_root,
.alloc_block = xfs_inobt_alloc_block,
.free_block = xfs_inobt_free_block,
.get_minrecs = xfs_inobt_get_minrecs,
.get_maxrecs = xfs_inobt_get_maxrecs,
.init_key_from_rec = xfs_inobt_init_key_from_rec,
.init_rec_from_key = xfs_inobt_init_rec_from_key,
.init_rec_from_cur = xfs_inobt_init_rec_from_cur,
.init_ptr_from_cur = xfs_finobt_init_ptr_from_cur,
.key_diff = xfs_inobt_key_diff,
.buf_ops = &xfs_inobt_buf_ops,
#if defined(DEBUG) || defined(XFS_WARN)
.keys_inorder = xfs_inobt_keys_inorder,
.recs_inorder = xfs_inobt_recs_inorder,
#endif
};
/*
* Allocate a new inode btree cursor.
*/
@ -325,7 +375,8 @@ xfs_inobt_init_cursor(
struct xfs_mount *mp, /* file system mount point */
struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer for agi structure */
xfs_agnumber_t agno) /* allocation group number */
xfs_agnumber_t agno, /* allocation group number */
xfs_btnum_t btnum) /* ialloc or free ino btree */
{
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
struct xfs_btree_cur *cur;
@ -334,11 +385,17 @@ xfs_inobt_init_cursor(
cur->bc_tp = tp;
cur->bc_mp = mp;
cur->bc_nlevels = be32_to_cpu(agi->agi_level);
cur->bc_btnum = XFS_BTNUM_INO;
cur->bc_btnum = btnum;
if (btnum == XFS_BTNUM_INO) {
cur->bc_nlevels = be32_to_cpu(agi->agi_level);
cur->bc_ops = &xfs_inobt_ops;
} else {
cur->bc_nlevels = be32_to_cpu(agi->agi_free_level);
cur->bc_ops = &xfs_finobt_ops;
}
cur->bc_blocklog = mp->m_sb.sb_blocklog;
cur->bc_ops = &xfs_inobt_ops;
if (xfs_sb_version_hascrc(&mp->m_sb))
cur->bc_flags |= XFS_BTREE_CRC_BLOCKS;

View file

@ -58,7 +58,8 @@ struct xfs_mount;
((index) - 1) * sizeof(xfs_inobt_ptr_t)))
extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t);
struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t,
xfs_btnum_t);
extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
#endif /* __XFS_IALLOC_BTREE_H__ */

View file

@ -507,8 +507,7 @@ STATIC int
xfs_inode_ag_walk(
struct xfs_mount *mp,
struct xfs_perag *pag,
int (*execute)(struct xfs_inode *ip,
struct xfs_perag *pag, int flags,
int (*execute)(struct xfs_inode *ip, int flags,
void *args),
int flags,
void *args,
@ -582,7 +581,7 @@ xfs_inode_ag_walk(
for (i = 0; i < nr_found; i++) {
if (!batch[i])
continue;
error = execute(batch[i], pag, flags, args);
error = execute(batch[i], flags, args);
IRELE(batch[i]);
if (error == EAGAIN) {
skipped++;
@ -636,8 +635,7 @@ xfs_eofblocks_worker(
int
xfs_inode_ag_iterator(
struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip,
struct xfs_perag *pag, int flags,
int (*execute)(struct xfs_inode *ip, int flags,
void *args),
int flags,
void *args)
@ -664,8 +662,7 @@ xfs_inode_ag_iterator(
int
xfs_inode_ag_iterator_tag(
struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip,
struct xfs_perag *pag, int flags,
int (*execute)(struct xfs_inode *ip, int flags,
void *args),
int flags,
void *args,
@ -1209,7 +1206,6 @@ xfs_inode_match_id(
STATIC int
xfs_inode_free_eofblocks(
struct xfs_inode *ip,
struct xfs_perag *pag,
int flags,
void *args)
{

View file

@ -60,12 +60,10 @@ int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *);
void xfs_eofblocks_worker(struct work_struct *);
int xfs_inode_ag_iterator(struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag,
int flags, void *args),
int (*execute)(struct xfs_inode *ip, int flags, void *args),
int flags, void *args);
int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag,
int flags, void *args),
int (*execute)(struct xfs_inode *ip, int flags, void *args),
int flags, void *args, int tag);
static inline int

View file

@ -655,7 +655,6 @@ xfs_ialloc(
uint flags;
int error;
timespec_t tv;
int filestreams = 0;
/*
* Call the space management code to pick
@ -682,6 +681,14 @@ xfs_ialloc(
return error;
ASSERT(ip != NULL);
/*
* We always convert v1 inodes to v2 now - we only support filesystems
* with >= v2 inode capability, so there is no reason for ever leaving
* an inode in v1 format.
*/
if (ip->i_d.di_version == 1)
ip->i_d.di_version = 2;
ip->i_d.di_mode = mode;
ip->i_d.di_onlink = 0;
ip->i_d.di_nlink = nlink;
@ -691,27 +698,6 @@ xfs_ialloc(
xfs_set_projid(ip, prid);
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
/*
* If the superblock version is up to where we support new format
* inodes and this is currently an old format inode, then change
* the inode version number now. This way we only do the conversion
* here rather than here and in the flush/logging code.
*/
if (xfs_sb_version_hasnlink(&mp->m_sb) &&
ip->i_d.di_version == 1) {
ip->i_d.di_version = 2;
/*
* We've already zeroed the old link count, the projid field,
* and the pad field.
*/
}
/*
* Project ids won't be stored on disk if we are using a version 1 inode.
*/
if ((prid != 0) && (ip->i_d.di_version == 1))
xfs_bump_ino_vers2(tp, ip);
if (pip && XFS_INHERIT_GID(pip)) {
ip->i_d.di_gid = pip->i_d.di_gid;
if ((pip->i_d.di_mode & S_ISGID) && S_ISDIR(mode)) {
@ -772,13 +758,6 @@ xfs_ialloc(
flags |= XFS_ILOG_DEV;
break;
case S_IFREG:
/*
* we can't set up filestreams until after the VFS inode
* is set up properly.
*/
if (pip && xfs_inode_is_filestream(pip))
filestreams = 1;
/* fall through */
case S_IFDIR:
if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
uint di_flags = 0;
@ -844,15 +823,6 @@ xfs_ialloc(
/* now that we have an i_mode we can setup inode ops and unlock */
xfs_setup_inode(ip);
/* now we have set up the vfs inode we can associate the filestream */
if (filestreams) {
error = xfs_filestream_associate(pip, ip);
if (error < 0)
return -error;
if (!error)
xfs_iflags_set(ip, XFS_IFILESTREAM);
}
*ipp = ip;
return 0;
}
@ -1072,40 +1042,6 @@ xfs_droplink(
return error;
}
/*
* This gets called when the inode's version needs to be changed from 1 to 2.
* Currently this happens when the nlink field overflows the old 16-bit value
* or when chproj is called to change the project for the first time.
* As a side effect the superblock version will also get rev'd
* to contain the NLINK bit.
*/
void
xfs_bump_ino_vers2(
xfs_trans_t *tp,
xfs_inode_t *ip)
{
xfs_mount_t *mp;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_d.di_version == 1);
ip->i_d.di_version = 2;
ip->i_d.di_onlink = 0;
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
mp = tp->t_mountp;
if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
spin_lock(&mp->m_sb_lock);
if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
xfs_sb_version_addnlink(&mp->m_sb);
spin_unlock(&mp->m_sb_lock);
xfs_mod_sb(tp, XFS_SB_VERSIONNUM);
} else {
spin_unlock(&mp->m_sb_lock);
}
}
/* Caller must log the inode */
}
/*
* Increment the link count on an inode & log the change.
*/
@ -1116,22 +1052,10 @@ xfs_bumplink(
{
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
ASSERT(ip->i_d.di_version > 1);
ASSERT(ip->i_d.di_nlink > 0 || (VFS_I(ip)->i_state & I_LINKABLE));
ip->i_d.di_nlink++;
inc_nlink(VFS_I(ip));
if ((ip->i_d.di_version == 1) &&
(ip->i_d.di_nlink > XFS_MAXLINK_1)) {
/*
* The inode has increased its number of links beyond
* what can fit in an old format inode. It now needs
* to be converted to a version 2 inode with a 32 bit
* link count. If this is the first inode in the file
* system to do this, then we need to bump the superblock
* version number as well.
*/
xfs_bump_ino_vers2(tp, ip);
}
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
return 0;
}
@ -1698,16 +1622,6 @@ xfs_release(
if (!XFS_FORCED_SHUTDOWN(mp)) {
int truncated;
/*
* If we are using filestreams, and we have an unlinked
* file that we are processing the last close on, then nothing
* will be able to reopen and write to this file. Purge this
* inode from the filestreams cache so that it doesn't delay
* teardown of the inode.
*/
if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
xfs_filestream_deassociate(ip);
/*
* If we previously truncated this file and removed old data
* in the process, we want to initiate "early" writeout on
@ -1838,9 +1752,33 @@ xfs_inactive_ifree(
int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
/*
* The ifree transaction might need to allocate blocks for record
* insertion to the finobt. We don't want to fail here at ENOSPC, so
* allow ifree to dip into the reserved block pool if necessary.
*
* Freeing large sets of inodes generally means freeing inode chunks,
* directory and file data blocks, so this should be relatively safe.
* Only under severe circumstances should it be possible to free enough
* inodes to exhaust the reserve block pool via finobt expansion while
* at the same time not creating free space in the filesystem.
*
* Send a warning if the reservation does happen to fail, as the inode
* now remains allocated and sits on the unlinked list until the fs is
* repaired.
*/
tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
XFS_IFREE_SPACE_RES(mp), 0);
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
if (error == ENOSPC) {
xfs_warn_ratelimited(mp,
"Failed to remove inode(s) from unlinked list. "
"Please free space, unmount and run xfs_repair.");
} else {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
}
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
return error;
}
@ -2664,13 +2602,7 @@ xfs_remove(
if (error)
goto std_return;
/*
* If we are using filestreams, kill the stream association.
* If the file is still open it may get a new one but that
* will get killed on last close in xfs_close() so we don't
* have to worry about that.
*/
if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
if (is_dir && xfs_inode_is_filestream(ip))
xfs_filestream_deassociate(ip);
return 0;
@ -3258,6 +3190,7 @@ xfs_iflush_int(
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK));
ASSERT(iip != NULL && iip->ili_fields != 0);
ASSERT(ip->i_d.di_version > 1);
/* set *dip = inode's place in the buffer */
dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
@ -3318,7 +3251,7 @@ xfs_iflush_int(
}
/*
* Inode item log recovery for v1/v2 inodes are dependent on the
* Inode item log recovery for v2 inodes are dependent on the
* di_flushiter count for correct sequencing. We bump the flush
* iteration count so we can detect flushes which postdate a log record
* during recovery. This is redundant as we now log every change and
@ -3341,40 +3274,9 @@ xfs_iflush_int(
if (ip->i_d.di_flushiter == DI_MAX_FLUSH)
ip->i_d.di_flushiter = 0;
/*
* If this is really an old format inode and the superblock version
* has not been updated to support only new format inodes, then
* convert back to the old inode format. If the superblock version
* has been updated, then make the conversion permanent.
*/
ASSERT(ip->i_d.di_version == 1 || xfs_sb_version_hasnlink(&mp->m_sb));
if (ip->i_d.di_version == 1) {
if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
/*
* Convert it back.
*/
ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1);
dip->di_onlink = cpu_to_be16(ip->i_d.di_nlink);
} else {
/*
* The superblock version has already been bumped,
* so just make the conversion to the new inode
* format permanent.
*/
ip->i_d.di_version = 2;
dip->di_version = 2;
ip->i_d.di_onlink = 0;
dip->di_onlink = 0;
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
memset(&(dip->di_pad[0]), 0,
sizeof(dip->di_pad));
ASSERT(xfs_get_projid(ip) == 0);
}
}
xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK, bp);
xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK);
if (XFS_IFORK_Q(ip))
xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK, bp);
xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK);
xfs_inobp_check(mp, bp);
/*

View file

@ -209,7 +209,6 @@ xfs_get_initial_prid(struct xfs_inode *dp)
#define XFS_ISTALE (1 << 1) /* inode has been staled */
#define XFS_IRECLAIMABLE (1 << 2) /* inode can be reclaimed */
#define XFS_INEW (1 << 3) /* inode has just been allocated */
#define XFS_IFILESTREAM (1 << 4) /* inode is in a filestream dir. */
#define XFS_ITRUNCATED (1 << 5) /* truncated down so flush-on-close */
#define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */
#define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */
@ -225,8 +224,7 @@ xfs_get_initial_prid(struct xfs_inode *dp)
*/
#define XFS_IRECLAIM_RESET_FLAGS \
(XFS_IRECLAIMABLE | XFS_IRECLAIM | \
XFS_IDIRTY_RELEASE | XFS_ITRUNCATED | \
XFS_IFILESTREAM);
XFS_IDIRTY_RELEASE | XFS_ITRUNCATED)
/*
* Synchronize processes attempting to flush the in-core inode back to disk.
@ -379,7 +377,6 @@ int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t,
struct xfs_inode **, int *);
int xfs_droplink(struct xfs_trans *, struct xfs_inode *);
int xfs_bumplink(struct xfs_trans *, struct xfs_inode *);
void xfs_bump_ino_vers2(struct xfs_trans *, struct xfs_inode *);
/* from xfs_file.c */
int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);

View file

@ -437,17 +437,16 @@ xfs_iread(
}
/*
* The inode format changed when we moved the link count and
* made it 32 bits long. If this is an old format inode,
* convert it in memory to look like a new one. If it gets
* flushed to disk we will convert back before flushing or
* logging it. We zero out the new projid field and the old link
* count field. We'll handle clearing the pad field (the remains
* of the old uuid field) when we actually convert the inode to
* the new format. We don't change the version number so that we
* can distinguish this from a real new format inode.
* Automatically convert version 1 inode formats in memory to version 2
* inode format. If the inode is modified, it will get logged and
* rewritten as a version 2 inode. We can do this because we set the
* superblock feature bit for v2 inodes unconditionally during mount
* and it means the reast of the code can assume the inode version is 2
* or higher.
*/
if (ip->i_d.di_version == 1) {
ip->i_d.di_version = 2;
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
ip->i_d.di_nlink = ip->i_d.di_onlink;
ip->i_d.di_onlink = 0;
xfs_set_projid(ip, 0);

View file

@ -798,8 +798,7 @@ xfs_iflush_fork(
xfs_inode_t *ip,
xfs_dinode_t *dip,
xfs_inode_log_item_t *iip,
int whichfork,
xfs_buf_t *bp)
int whichfork)
{
char *cp;
xfs_ifork_t *ifp;

View file

@ -127,8 +127,7 @@ typedef struct xfs_ifork {
int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *);
void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *,
struct xfs_inode_log_item *, int,
struct xfs_buf *);
struct xfs_inode_log_item *, int);
void xfs_idestroy_fork(struct xfs_inode *, int);
void xfs_idata_realloc(struct xfs_inode *, int, int);
void xfs_iroot_realloc(struct xfs_inode *, int, int);

View file

@ -145,34 +145,6 @@ xfs_inode_item_size(
xfs_inode_item_attr_fork_size(iip, nvecs, nbytes);
}
/*
* If this is a v1 format inode, then we need to log it as such. This means
* that we have to copy the link count from the new field to the old. We
* don't have to worry about the new fields, because nothing trusts them as
* long as the old inode version number is there.
*/
STATIC void
xfs_inode_item_format_v1_inode(
struct xfs_inode *ip)
{
if (!xfs_sb_version_hasnlink(&ip->i_mount->m_sb)) {
/*
* Convert it back.
*/
ASSERT(ip->i_d.di_nlink <= XFS_MAXLINK_1);
ip->i_d.di_onlink = ip->i_d.di_nlink;
} else {
/*
* The superblock version has already been bumped,
* so just make the conversion to the new inode
* format permanent.
*/
ip->i_d.di_version = 2;
ip->i_d.di_onlink = 0;
memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
}
}
STATIC void
xfs_inode_item_format_data_fork(
struct xfs_inode_log_item *iip,
@ -370,6 +342,8 @@ xfs_inode_item_format(
struct xfs_inode_log_format *ilf;
struct xfs_log_iovec *vecp = NULL;
ASSERT(ip->i_d.di_version > 1);
ilf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_IFORMAT);
ilf->ilf_type = XFS_LI_INODE;
ilf->ilf_ino = ip->i_ino;
@ -380,8 +354,6 @@ xfs_inode_item_format(
ilf->ilf_size = 2; /* format + core */
xlog_finish_iovec(lv, vecp, sizeof(struct xfs_inode_log_format));
if (ip->i_d.di_version == 1)
xfs_inode_item_format_v1_inode(ip);
xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ICORE,
&ip->i_d,
xfs_icdinode_size(ip->i_d.di_version));

View file

@ -543,10 +543,11 @@ xfs_attrmulti_by_handle(
ops = memdup_user(am_hreq.ops, size);
if (IS_ERR(ops)) {
error = PTR_ERR(ops);
error = -PTR_ERR(ops);
goto out_dput;
}
error = ENOMEM;
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
if (!attr_name)
goto out_kfree_ops;
@ -556,7 +557,7 @@ xfs_attrmulti_by_handle(
ops[i].am_error = strncpy_from_user((char *)attr_name,
ops[i].am_attrname, MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
error = -ERANGE;
error = ERANGE;
if (ops[i].am_error < 0)
break;
@ -1227,15 +1228,8 @@ xfs_ioctl_setattr(
olddquot = xfs_qm_vop_chown(tp, ip,
&ip->i_pdquot, pdqp);
}
ASSERT(ip->i_d.di_version > 1);
xfs_set_projid(ip, fa->fsx_projid);
/*
* We may have to rev the inode as well as
* the superblock version number since projids didn't
* exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
*/
if (ip->i_d.di_version == 1)
xfs_bump_ino_vers2(tp, ip);
}
}

View file

@ -424,10 +424,11 @@ xfs_compat_attrmulti_by_handle(
ops = memdup_user(compat_ptr(am_hreq.ops), size);
if (IS_ERR(ops)) {
error = PTR_ERR(ops);
error = -PTR_ERR(ops);
goto out_dput;
}
error = ENOMEM;
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
if (!attr_name)
goto out_kfree_ops;
@ -438,7 +439,7 @@ xfs_compat_attrmulti_by_handle(
compat_ptr(ops[i].am_attrname),
MAXNAMELEN);
if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
error = -ERANGE;
error = ERANGE;
if (ops[i].am_error < 0)
break;

View file

@ -730,7 +730,7 @@ xfs_iomap_write_allocate(
*/
nimaps = 1;
end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip));
error = xfs_bmap_last_offset(NULL, ip, &last_block,
error = xfs_bmap_last_offset(ip, &last_block,
XFS_DATA_FORK);
if (error)
goto trans_cancel;

View file

@ -829,22 +829,34 @@ xfs_setattr_size(
*/
inode_dio_wait(inode);
/*
* Do all the page cache truncate work outside the transaction context
* as the "lock" order is page lock->log space reservation. i.e.
* locking pages inside the transaction can ABBA deadlock with
* writeback. We have to do the VFS inode size update before we truncate
* the pagecache, however, to avoid racing with page faults beyond the
* new EOF they are not serialised against truncate operations except by
* page locks and size updates.
*
* Hence we are in a situation where a truncate can fail with ENOMEM
* from xfs_trans_reserve(), but having already truncated the in-memory
* version of the file (i.e. made user visible changes). There's not
* much we can do about this, except to hope that the caller sees ENOMEM
* and retries the truncate operation.
*/
error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks);
if (error)
return error;
truncate_setsize(inode, newsize);
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
if (error)
goto out_trans_cancel;
truncate_setsize(inode, newsize);
commit_flags = XFS_TRANS_RELEASE_LOG_RES;
lock_flags |= XFS_ILOCK_EXCL;
xfs_ilock(ip, XFS_ILOCK_EXCL);
xfs_trans_ijoin(tp, ip, 0);
/*

View file

@ -270,7 +270,8 @@ xfs_bulkstat(
/*
* Allocate and initialize a btree cursor for ialloc btree.
*/
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
XFS_BTNUM_INO);
irbp = irbuf;
irbufend = irbuf + nirbuf;
end_of_ag = 0;
@ -621,7 +622,8 @@ xfs_inumbers(
agino = 0;
continue;
}
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno,
XFS_BTNUM_INO);
error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE,
&tmp);
if (error) {

View file

@ -1165,7 +1165,7 @@ xlog_iodone(xfs_buf_t *bp)
/*
* Race to shutdown the filesystem if we see an error.
*/
if (XFS_TEST_ERROR((xfs_buf_geterror(bp)), l->l_mp,
if (XFS_TEST_ERROR(bp->b_error, l->l_mp,
XFS_ERRTAG_IODONE_IOERR, XFS_RANDOM_IODONE_IOERR)) {
xfs_buf_ioerror_alert(bp, __func__);
xfs_buf_stale(bp);
@ -3952,11 +3952,14 @@ xfs_log_force_umount(
retval = xlog_state_ioerror(log);
spin_unlock(&log->l_icloglock);
}
/*
* Wake up everybody waiting on xfs_log_force.
* Callback all log item committed functions as if the
* log writes were completed.
* Wake up everybody waiting on xfs_log_force. Wake the CIL push first
* as if the log writes were completed. The abort handling in the log
* item committed callback functions will do this again under lock to
* avoid races.
*/
wake_up_all(&log->l_cilp->xc_commit_wait);
xlog_state_do_callback(log, XFS_LI_ABORTED, NULL);
#ifdef XFSERRORDEBUG

View file

@ -24,7 +24,8 @@ struct xfs_log_vec {
struct xfs_log_iovec *lv_iovecp; /* iovec array */
struct xfs_log_item *lv_item; /* owner */
char *lv_buf; /* formatted buffer */
int lv_buf_len; /* size of formatted buffer */
int lv_bytes; /* accounted space in buffer */
int lv_buf_len; /* aligned size of buffer */
int lv_size; /* size of allocated lv */
};
@ -52,15 +53,21 @@ xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp,
return vec->i_addr;
}
/*
* We need to make sure the next buffer is naturally aligned for the biggest
* basic data type we put into it. We already accounted for this padding when
* sizing the buffer.
*
* However, this padding does not get written into the log, and hence we have to
* track the space used by the log vectors separately to prevent log space hangs
* due to inaccurate accounting (i.e. a leak) of the used log space through the
* CIL context ticket.
*/
static inline void
xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len)
{
/*
* We need to make sure the next buffer is naturally aligned for the
* biggest basic data type we put into it. We already accounted for
* this when sizing the buffer.
*/
lv->lv_buf_len += round_up(len, sizeof(uint64_t));
lv->lv_bytes += len;
vec->i_len = len;
}

View file

@ -97,7 +97,7 @@ xfs_cil_prepare_item(
{
/* Account for the new LV being passed in */
if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) {
*diff_len += lv->lv_buf_len;
*diff_len += lv->lv_bytes;
*diff_iovecs += lv->lv_niovecs;
}
@ -111,7 +111,7 @@ xfs_cil_prepare_item(
else if (old_lv != lv) {
ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED);
*diff_len -= old_lv->lv_buf_len;
*diff_len -= old_lv->lv_bytes;
*diff_iovecs -= old_lv->lv_niovecs;
kmem_free(old_lv);
}
@ -239,7 +239,7 @@ xlog_cil_insert_format_items(
* that the space reservation accounting is correct.
*/
*diff_iovecs -= lv->lv_niovecs;
*diff_len -= lv->lv_buf_len;
*diff_len -= lv->lv_bytes;
} else {
/* allocate new data chunk */
lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS);
@ -259,6 +259,7 @@ xlog_cil_insert_format_items(
/* The allocated data region lies beyond the iovec region */
lv->lv_buf_len = 0;
lv->lv_bytes = 0;
lv->lv_buf = (char *)lv + buf_size - nbytes;
ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t)));
@ -385,7 +386,15 @@ xlog_cil_committed(
xfs_extent_busy_clear(mp, &ctx->busy_extents,
(mp->m_flags & XFS_MOUNT_DISCARD) && !abort);
/*
* If we are aborting the commit, wake up anyone waiting on the
* committing list. If we don't, then a shutdown we can leave processes
* waiting in xlog_cil_force_lsn() waiting on a sequence commit that
* will never happen because we aborted it.
*/
spin_lock(&ctx->cil->xc_push_lock);
if (abort)
wake_up_all(&ctx->cil->xc_commit_wait);
list_del(&ctx->committing);
spin_unlock(&ctx->cil->xc_push_lock);
@ -563,9 +572,19 @@ xlog_cil_push(
restart:
spin_lock(&cil->xc_push_lock);
list_for_each_entry(new_ctx, &cil->xc_committing, committing) {
/*
* Avoid getting stuck in this loop because we were woken by the
* shutdown, but then went back to sleep once already in the
* shutdown state.
*/
if (XLOG_FORCED_SHUTDOWN(log)) {
spin_unlock(&cil->xc_push_lock);
goto out_abort_free_ticket;
}
/*
* Higher sequences will wait for this one so skip them.
* Don't wait for own own sequence, either.
* Don't wait for our own sequence, either.
*/
if (new_ctx->sequence >= ctx->sequence)
continue;
@ -810,6 +829,13 @@ xlog_cil_force_lsn(
*/
spin_lock(&cil->xc_push_lock);
list_for_each_entry(ctx, &cil->xc_committing, committing) {
/*
* Avoid getting stuck in this loop because we were woken by the
* shutdown, but then went back to sleep once already in the
* shutdown state.
*/
if (XLOG_FORCED_SHUTDOWN(log))
goto out_shutdown;
if (ctx->sequence > sequence)
continue;
if (!ctx->commit_lsn) {
@ -833,14 +859,12 @@ xlog_cil_force_lsn(
* push sequence after the above wait loop and the CIL still contains
* dirty objects.
*
* When the push occurs, it will empty the CIL and
* atomically increment the currect sequence past the push sequence and
* move it into the committing list. Of course, if the CIL is clean at
* the time of the push, it won't have pushed the CIL at all, so in that
* case we should try the push for this sequence again from the start
* just in case.
* When the push occurs, it will empty the CIL and atomically increment
* the currect sequence past the push sequence and move it into the
* committing list. Of course, if the CIL is clean at the time of the
* push, it won't have pushed the CIL at all, so in that case we should
* try the push for this sequence again from the start just in case.
*/
if (sequence == cil->xc_current_sequence &&
!list_empty(&cil->xc_cil)) {
spin_unlock(&cil->xc_push_lock);
@ -849,6 +873,17 @@ xlog_cil_force_lsn(
spin_unlock(&cil->xc_push_lock);
return commit_lsn;
/*
* We detected a shutdown in progress. We need to trigger the log force
* to pass through it's iclog state machine error handling, even though
* we are already in a shutdown state. Hence we can't return
* NULLCOMMITLSN here as that has special meaning to log forces (i.e.
* LSN is already stable), so we return a zero LSN instead.
*/
out_shutdown:
spin_unlock(&cil->xc_push_lock);
return 0;
}
/*

View file

@ -2138,7 +2138,9 @@ xlog_recover_validate_buf_type(
bp->b_ops = &xfs_allocbt_buf_ops;
break;
case XFS_IBT_CRC_MAGIC:
case XFS_FIBT_CRC_MAGIC:
case XFS_IBT_MAGIC:
case XFS_FIBT_MAGIC:
bp->b_ops = &xfs_inobt_buf_ops;
break;
case XFS_BMAP_CRC_MAGIC:
@ -3145,7 +3147,7 @@ xlog_recover_efd_pass2(
}
lip = xfs_trans_ail_cursor_next(ailp, &cur);
}
xfs_trans_ail_cursor_done(ailp, &cur);
xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock);
return 0;
@ -3520,8 +3522,7 @@ xlog_recover_commit_trans(
STATIC int
xlog_recover_unmount_trans(
struct xlog *log,
struct xlog_recover *trans)
struct xlog *log)
{
/* Do nothing now */
xfs_warn(log->l_mp, "%s: Unmount LR", __func__);
@ -3595,7 +3596,7 @@ xlog_recover_process_data(
trans, pass);
break;
case XLOG_UNMOUNT_TRANS:
error = xlog_recover_unmount_trans(log, trans);
error = xlog_recover_unmount_trans(log);
break;
case XLOG_WAS_CONT_TRANS:
error = xlog_recover_add_to_cont_trans(log,
@ -3757,7 +3758,7 @@ xlog_recover_process_efis(
lip = xfs_trans_ail_cursor_next(ailp, &cur);
}
out:
xfs_trans_ail_cursor_done(ailp, &cur);
xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock);
return error;
}

View file

@ -42,7 +42,7 @@ xfs_log_calc_max_attrsetm_res(
int size;
int nblks;
size = xfs_attr_leaf_entsize_local_max(mp->m_sb.sb_blocksize) -
size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) -
MAXNAMELEN - 1;
nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
nblks += XFS_B_TO_FSB(mp, size);

View file

@ -323,8 +323,19 @@ xfs_readsb(
/*
* Initialize the mount structure from the superblock.
*/
xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
xfs_sb_quota_from_disk(&mp->m_sb);
xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp));
xfs_sb_quota_from_disk(sbp);
/*
* If we haven't validated the superblock, do so now before we try
* to check the sector size and reread the superblock appropriately.
*/
if (sbp->sb_magicnum != XFS_SB_MAGIC) {
if (loud)
xfs_warn(mp, "Invalid superblock magic number");
error = EINVAL;
goto release_buf;
}
/*
* We must be able to do sector-sized and sector-aligned IO.
@ -337,11 +348,11 @@ xfs_readsb(
goto release_buf;
}
/*
* Re-read the superblock so the buffer is correctly sized,
* and properly verified.
*/
if (buf_ops == NULL) {
/*
* Re-read the superblock so the buffer is correctly sized,
* and properly verified.
*/
xfs_buf_relse(bp);
sector_size = sbp->sb_sectsize;
buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops;
@ -697,6 +708,12 @@ xfs_mountfs(
mp->m_update_flags |= XFS_SB_VERSIONNUM;
}
/* always use v2 inodes by default now */
if (!(mp->m_sb.sb_versionnum & XFS_SB_VERSION_NLINKBIT)) {
mp->m_sb.sb_versionnum |= XFS_SB_VERSION_NLINKBIT;
mp->m_update_flags |= XFS_SB_VERSIONNUM;
}
/*
* Check if sb_agblocks is aligned at stripe boundary
* If sb_agblocks is NOT aligned turn off m_dalign since
@ -774,12 +791,11 @@ xfs_mountfs(
mp->m_dmevmask = 0; /* not persistent; set after each mount */
xfs_dir_mount(mp);
/*
* Initialize the attribute manager's entries.
*/
mp->m_attr_magicpct = (mp->m_sb.sb_blocksize * 37) / 100;
error = xfs_da_mount(mp);
if (error) {
xfs_warn(mp, "Failed dir/attr init: %d", error);
goto out_remove_uuid;
}
/*
* Initialize the precomputed transaction reservations values.
@ -794,7 +810,7 @@ xfs_mountfs(
error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
if (error) {
xfs_warn(mp, "Failed per-ag init: %d", error);
goto out_remove_uuid;
goto out_free_dir;
}
if (!sbp->sb_logblocks) {
@ -969,6 +985,8 @@ xfs_mountfs(
xfs_wait_buftarg(mp->m_ddev_targp);
out_free_perag:
xfs_free_perag(mp);
out_free_dir:
xfs_da_unmount(mp);
out_remove_uuid:
xfs_uuid_unmount(mp);
out:
@ -1046,6 +1064,7 @@ xfs_unmountfs(
"Freespace may not be correct on next mount.");
xfs_log_unmount(mp);
xfs_da_unmount(mp);
xfs_uuid_unmount(mp);
#if defined(DEBUG)

View file

@ -27,6 +27,7 @@ struct xfs_nameops;
struct xfs_ail;
struct xfs_quotainfo;
struct xfs_dir_ops;
struct xfs_da_geometry;
#ifdef HAVE_PERCPU_SB
@ -96,6 +97,8 @@ typedef struct xfs_mount {
uint m_readio_blocks; /* min read size blocks */
uint m_writeio_log; /* min write size log bytes */
uint m_writeio_blocks; /* min write size blocks */
struct xfs_da_geometry *m_dir_geo; /* directory block geometry */
struct xfs_da_geometry *m_attr_geo; /* attribute block geometry */
struct xlog *m_log; /* log specific stuff */
int m_logbufs; /* number of log buffers */
int m_logbsize; /* size of each log buffer */
@ -131,8 +134,6 @@ typedef struct xfs_mount {
int m_fixedfsid[2]; /* unchanged for life of FS */
uint m_dmevmask; /* DMI events for this FS */
__uint64_t m_flags; /* global mount flags */
uint m_dir_node_ents; /* #entries in a dir danode */
uint m_attr_node_ents; /* #entries in attr danode */
int m_ialloc_inos; /* inodes in inode allocation */
int m_ialloc_blks; /* blocks in inode allocation */
int m_inoalign_mask;/* mask sb_inoalignmt if used */
@ -145,17 +146,10 @@ typedef struct xfs_mount {
int m_dalign; /* stripe unit */
int m_swidth; /* stripe width */
int m_sinoalign; /* stripe unit inode alignment */
int m_attr_magicpct;/* 37% of the blocksize */
int m_dir_magicpct; /* 37% of the dir blocksize */
__uint8_t m_sectbb_log; /* sectlog - BBSHIFT */
const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */
const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */
const struct xfs_dir_ops *m_nondir_inode_ops; /* !dir inode ops */
int m_dirblksize; /* directory block sz--bytes */
int m_dirblkfsbs; /* directory block sz--fsbs */
xfs_dablk_t m_dirdatablk; /* blockno of dir data v2 */
xfs_dablk_t m_dirleafblk; /* blockno of dir non-data v2 */
xfs_dablk_t m_dirfreeblk; /* blockno of dirfreeindex v2 */
uint m_chsize; /* size of next field */
atomic_t m_active_trans; /* number trans frozen */
#ifdef HAVE_PERCPU_SB

View file

@ -100,14 +100,20 @@
* likely result in a loop in one of the lists. That's a sure-fire recipe for
* an infinite loop in the code.
*/
typedef struct xfs_mru_cache_elem
{
struct list_head list_node;
unsigned long key;
void *value;
} xfs_mru_cache_elem_t;
struct xfs_mru_cache {
struct radix_tree_root store; /* Core storage data structure. */
struct list_head *lists; /* Array of lists, one per grp. */
struct list_head reap_list; /* Elements overdue for reaping. */
spinlock_t lock; /* Lock to protect this struct. */
unsigned int grp_count; /* Number of discrete groups. */
unsigned int grp_time; /* Time period spanned by grps. */
unsigned int lru_grp; /* Group containing time zero. */
unsigned long time_zero; /* Time first element was added. */
xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
struct delayed_work work; /* Workqueue data for reaping. */
unsigned int queued; /* work has been queued */
};
static kmem_zone_t *xfs_mru_elem_zone;
static struct workqueue_struct *xfs_mru_reap_wq;
/*
@ -129,12 +135,12 @@ static struct workqueue_struct *xfs_mru_reap_wq;
*/
STATIC unsigned long
_xfs_mru_cache_migrate(
xfs_mru_cache_t *mru,
unsigned long now)
struct xfs_mru_cache *mru,
unsigned long now)
{
unsigned int grp;
unsigned int migrated = 0;
struct list_head *lru_list;
unsigned int grp;
unsigned int migrated = 0;
struct list_head *lru_list;
/* Nothing to do if the data store is empty. */
if (!mru->time_zero)
@ -193,11 +199,11 @@ _xfs_mru_cache_migrate(
*/
STATIC void
_xfs_mru_cache_list_insert(
xfs_mru_cache_t *mru,
xfs_mru_cache_elem_t *elem)
struct xfs_mru_cache *mru,
struct xfs_mru_cache_elem *elem)
{
unsigned int grp = 0;
unsigned long now = jiffies;
unsigned int grp = 0;
unsigned long now = jiffies;
/*
* If the data store is empty, initialise time zero, leave grp set to
@ -231,10 +237,10 @@ _xfs_mru_cache_list_insert(
*/
STATIC void
_xfs_mru_cache_clear_reap_list(
xfs_mru_cache_t *mru) __releases(mru->lock) __acquires(mru->lock)
struct xfs_mru_cache *mru)
__releases(mru->lock) __acquires(mru->lock)
{
xfs_mru_cache_elem_t *elem, *next;
struct xfs_mru_cache_elem *elem, *next;
struct list_head tmp;
INIT_LIST_HEAD(&tmp);
@ -252,15 +258,8 @@ _xfs_mru_cache_clear_reap_list(
spin_unlock(&mru->lock);
list_for_each_entry_safe(elem, next, &tmp, list_node) {
/* Remove the element from the reap list. */
list_del_init(&elem->list_node);
/* Call the client's free function with the key and value pointer. */
mru->free_func(elem->key, elem->value);
/* Free the element structure. */
kmem_zone_free(xfs_mru_elem_zone, elem);
mru->free_func(elem);
}
spin_lock(&mru->lock);
@ -277,7 +276,8 @@ STATIC void
_xfs_mru_cache_reap(
struct work_struct *work)
{
xfs_mru_cache_t *mru = container_of(work, xfs_mru_cache_t, work.work);
struct xfs_mru_cache *mru =
container_of(work, struct xfs_mru_cache, work.work);
unsigned long now, next;
ASSERT(mru && mru->lists);
@ -304,28 +304,16 @@ _xfs_mru_cache_reap(
int
xfs_mru_cache_init(void)
{
xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t),
"xfs_mru_cache_elem");
if (!xfs_mru_elem_zone)
goto out;
xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", WQ_MEM_RECLAIM, 1);
if (!xfs_mru_reap_wq)
goto out_destroy_mru_elem_zone;
return -ENOMEM;
return 0;
out_destroy_mru_elem_zone:
kmem_zone_destroy(xfs_mru_elem_zone);
out:
return -ENOMEM;
}
void
xfs_mru_cache_uninit(void)
{
destroy_workqueue(xfs_mru_reap_wq);
kmem_zone_destroy(xfs_mru_elem_zone);
}
/*
@ -336,14 +324,14 @@ xfs_mru_cache_uninit(void)
*/
int
xfs_mru_cache_create(
xfs_mru_cache_t **mrup,
struct xfs_mru_cache **mrup,
unsigned int lifetime_ms,
unsigned int grp_count,
xfs_mru_cache_free_func_t free_func)
{
xfs_mru_cache_t *mru = NULL;
int err = 0, grp;
unsigned int grp_time;
struct xfs_mru_cache *mru = NULL;
int err = 0, grp;
unsigned int grp_time;
if (mrup)
*mrup = NULL;
@ -400,7 +388,7 @@ xfs_mru_cache_create(
*/
static void
xfs_mru_cache_flush(
xfs_mru_cache_t *mru)
struct xfs_mru_cache *mru)
{
if (!mru || !mru->lists)
return;
@ -420,7 +408,7 @@ xfs_mru_cache_flush(
void
xfs_mru_cache_destroy(
xfs_mru_cache_t *mru)
struct xfs_mru_cache *mru)
{
if (!mru || !mru->lists)
return;
@ -438,38 +426,30 @@ xfs_mru_cache_destroy(
*/
int
xfs_mru_cache_insert(
xfs_mru_cache_t *mru,
unsigned long key,
void *value)
struct xfs_mru_cache *mru,
unsigned long key,
struct xfs_mru_cache_elem *elem)
{
xfs_mru_cache_elem_t *elem;
int error;
ASSERT(mru && mru->lists);
if (!mru || !mru->lists)
return EINVAL;
elem = kmem_zone_zalloc(xfs_mru_elem_zone, KM_SLEEP);
if (!elem)
if (radix_tree_preload(GFP_KERNEL))
return ENOMEM;
if (radix_tree_preload(GFP_KERNEL)) {
kmem_zone_free(xfs_mru_elem_zone, elem);
return ENOMEM;
}
INIT_LIST_HEAD(&elem->list_node);
elem->key = key;
elem->value = value;
spin_lock(&mru->lock);
radix_tree_insert(&mru->store, key, elem);
error = -radix_tree_insert(&mru->store, key, elem);
radix_tree_preload_end();
_xfs_mru_cache_list_insert(mru, elem);
if (!error)
_xfs_mru_cache_list_insert(mru, elem);
spin_unlock(&mru->lock);
return 0;
return error;
}
/*
@ -478,13 +458,12 @@ xfs_mru_cache_insert(
* the client data pointer for the removed element is returned, otherwise this
* function will return a NULL pointer.
*/
void *
struct xfs_mru_cache_elem *
xfs_mru_cache_remove(
xfs_mru_cache_t *mru,
unsigned long key)
struct xfs_mru_cache *mru,
unsigned long key)
{
xfs_mru_cache_elem_t *elem;
void *value = NULL;
struct xfs_mru_cache_elem *elem;
ASSERT(mru && mru->lists);
if (!mru || !mru->lists)
@ -492,17 +471,11 @@ xfs_mru_cache_remove(
spin_lock(&mru->lock);
elem = radix_tree_delete(&mru->store, key);
if (elem) {
value = elem->value;
if (elem)
list_del(&elem->list_node);
}
spin_unlock(&mru->lock);
if (elem)
kmem_zone_free(xfs_mru_elem_zone, elem);
return value;
return elem;
}
/*
@ -511,13 +484,14 @@ xfs_mru_cache_remove(
*/
void
xfs_mru_cache_delete(
xfs_mru_cache_t *mru,
unsigned long key)
struct xfs_mru_cache *mru,
unsigned long key)
{
void *value = xfs_mru_cache_remove(mru, key);
struct xfs_mru_cache_elem *elem;
if (value)
mru->free_func(key, value);
elem = xfs_mru_cache_remove(mru, key);
if (elem)
mru->free_func(elem);
}
/*
@ -540,12 +514,12 @@ xfs_mru_cache_delete(
* status, we need to help it get it right by annotating the path that does
* not release the lock.
*/
void *
struct xfs_mru_cache_elem *
xfs_mru_cache_lookup(
xfs_mru_cache_t *mru,
unsigned long key)
struct xfs_mru_cache *mru,
unsigned long key)
{
xfs_mru_cache_elem_t *elem;
struct xfs_mru_cache_elem *elem;
ASSERT(mru && mru->lists);
if (!mru || !mru->lists)
@ -560,7 +534,7 @@ xfs_mru_cache_lookup(
} else
spin_unlock(&mru->lock);
return elem ? elem->value : NULL;
return elem;
}
/*
@ -570,7 +544,8 @@ xfs_mru_cache_lookup(
*/
void
xfs_mru_cache_done(
xfs_mru_cache_t *mru) __releases(mru->lock)
struct xfs_mru_cache *mru)
__releases(mru->lock)
{
spin_unlock(&mru->lock);
}

View file

@ -18,24 +18,15 @@
#ifndef __XFS_MRU_CACHE_H__
#define __XFS_MRU_CACHE_H__
struct xfs_mru_cache;
struct xfs_mru_cache_elem {
struct list_head list_node;
unsigned long key;
};
/* Function pointer type for callback to free a client's data pointer. */
typedef void (*xfs_mru_cache_free_func_t)(unsigned long, void*);
typedef struct xfs_mru_cache
{
struct radix_tree_root store; /* Core storage data structure. */
struct list_head *lists; /* Array of lists, one per grp. */
struct list_head reap_list; /* Elements overdue for reaping. */
spinlock_t lock; /* Lock to protect this struct. */
unsigned int grp_count; /* Number of discrete groups. */
unsigned int grp_time; /* Time period spanned by grps. */
unsigned int lru_grp; /* Group containing time zero. */
unsigned long time_zero; /* Time first element was added. */
xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
struct delayed_work work; /* Workqueue data for reaping. */
unsigned int queued; /* work has been queued */
} xfs_mru_cache_t;
typedef void (*xfs_mru_cache_free_func_t)(struct xfs_mru_cache_elem *elem);
int xfs_mru_cache_init(void);
void xfs_mru_cache_uninit(void);
@ -44,10 +35,12 @@ int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
xfs_mru_cache_free_func_t free_func);
void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
void *value);
void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
struct xfs_mru_cache_elem *elem);
struct xfs_mru_cache_elem *
xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key);
void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
struct xfs_mru_cache_elem *
xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
void xfs_mru_cache_done(struct xfs_mru_cache *mru);
#endif /* __XFS_MRU_CACHE_H__ */

View file

@ -192,47 +192,6 @@ xfs_qm_dqpurge(
return 0;
}
/*
* Release the group or project dquot pointers the user dquots maybe carrying
* around as a hint, and proceed to purge the user dquot cache if requested.
*/
STATIC int
xfs_qm_dqpurge_hints(
struct xfs_dquot *dqp,
void *data)
{
struct xfs_dquot *gdqp = NULL;
struct xfs_dquot *pdqp = NULL;
uint flags = *((uint *)data);
xfs_dqlock(dqp);
if (dqp->dq_flags & XFS_DQ_FREEING) {
xfs_dqunlock(dqp);
return EAGAIN;
}
/* If this quota has a hint attached, prepare for releasing it now */
gdqp = dqp->q_gdquot;
if (gdqp)
dqp->q_gdquot = NULL;
pdqp = dqp->q_pdquot;
if (pdqp)
dqp->q_pdquot = NULL;
xfs_dqunlock(dqp);
if (gdqp)
xfs_qm_dqrele(gdqp);
if (pdqp)
xfs_qm_dqrele(pdqp);
if (flags & XFS_QMOPT_UQUOTA)
return xfs_qm_dqpurge(dqp, NULL);
return 0;
}
/*
* Purge the dquot cache.
*/
@ -241,18 +200,8 @@ xfs_qm_dqpurge_all(
struct xfs_mount *mp,
uint flags)
{
/*
* We have to release group/project dquot hint(s) from the user dquot
* at first if they are there, otherwise we would run into an infinite
* loop while walking through radix tree to purge other type of dquots
* since their refcount is not zero if the user dquot refers to them
* as hint.
*
* Call the special xfs_qm_dqpurge_hints() will end up go through the
* general xfs_qm_dqpurge() against user dquot cache if requested.
*/
xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge_hints, &flags);
if (flags & XFS_QMOPT_UQUOTA)
xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge, NULL);
if (flags & XFS_QMOPT_GQUOTA)
xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL);
if (flags & XFS_QMOPT_PQUOTA)
@ -409,7 +358,6 @@ xfs_qm_dqattach_one(
xfs_dqid_t id,
uint type,
uint doalloc,
xfs_dquot_t *udqhint, /* hint */
xfs_dquot_t **IO_idqpp)
{
xfs_dquot_t *dqp;
@ -419,9 +367,9 @@ xfs_qm_dqattach_one(
error = 0;
/*
* See if we already have it in the inode itself. IO_idqpp is
* &i_udquot or &i_gdquot. This made the code look weird, but
* made the logic a lot simpler.
* See if we already have it in the inode itself. IO_idqpp is &i_udquot
* or &i_gdquot. This made the code look weird, but made the logic a lot
* simpler.
*/
dqp = *IO_idqpp;
if (dqp) {
@ -430,49 +378,10 @@ xfs_qm_dqattach_one(
}
/*
* udqhint is the i_udquot field in inode, and is non-NULL only
* when the type arg is group/project. Its purpose is to save a
* lookup by dqid (xfs_qm_dqget) by caching a group dquot inside
* the user dquot.
*/
if (udqhint) {
ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
xfs_dqlock(udqhint);
/*
* No need to take dqlock to look at the id.
*
* The ID can't change until it gets reclaimed, and it won't
* be reclaimed as long as we have a ref from inode and we
* hold the ilock.
*/
if (type == XFS_DQ_GROUP)
dqp = udqhint->q_gdquot;
else
dqp = udqhint->q_pdquot;
if (dqp && be32_to_cpu(dqp->q_core.d_id) == id) {
ASSERT(*IO_idqpp == NULL);
*IO_idqpp = xfs_qm_dqhold(dqp);
xfs_dqunlock(udqhint);
return 0;
}
/*
* We can't hold a dquot lock when we call the dqget code.
* We'll deadlock in no time, because of (not conforming to)
* lock ordering - the inodelock comes before any dquot lock,
* and we may drop and reacquire the ilock in xfs_qm_dqget().
*/
xfs_dqunlock(udqhint);
}
/*
* Find the dquot from somewhere. This bumps the
* reference count of dquot and returns it locked.
* This can return ENOENT if dquot didn't exist on
* disk and we didn't ask it to allocate;
* ESRCH if quotas got turned off suddenly.
* Find the dquot from somewhere. This bumps the reference count of
* dquot and returns it locked. This can return ENOENT if dquot didn't
* exist on disk and we didn't ask it to allocate; ESRCH if quotas got
* turned off suddenly.
*/
error = xfs_qm_dqget(ip->i_mount, ip, id, type,
doalloc | XFS_QMOPT_DOWARN, &dqp);
@ -490,48 +399,6 @@ xfs_qm_dqattach_one(
return 0;
}
/*
* Given a udquot and group/project type, attach the group/project
* dquot pointer to the udquot as a hint for future lookups.
*/
STATIC void
xfs_qm_dqattach_hint(
struct xfs_inode *ip,
int type)
{
struct xfs_dquot **dqhintp;
struct xfs_dquot *dqp;
struct xfs_dquot *udq = ip->i_udquot;
ASSERT(type == XFS_DQ_GROUP || type == XFS_DQ_PROJ);
xfs_dqlock(udq);
if (type == XFS_DQ_GROUP) {
dqp = ip->i_gdquot;
dqhintp = &udq->q_gdquot;
} else {
dqp = ip->i_pdquot;
dqhintp = &udq->q_pdquot;
}
if (*dqhintp) {
struct xfs_dquot *tmp;
if (*dqhintp == dqp)
goto done;
tmp = *dqhintp;
*dqhintp = NULL;
xfs_qm_dqrele(tmp);
}
*dqhintp = xfs_qm_dqhold(dqp);
done:
xfs_dqunlock(udq);
}
static bool
xfs_qm_need_dqattach(
struct xfs_inode *ip)
@ -562,7 +429,6 @@ xfs_qm_dqattach_locked(
uint flags)
{
xfs_mount_t *mp = ip->i_mount;
uint nquotas = 0;
int error = 0;
if (!xfs_qm_need_dqattach(ip))
@ -570,77 +436,39 @@ xfs_qm_dqattach_locked(
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (XFS_IS_UQUOTA_ON(mp)) {
if (XFS_IS_UQUOTA_ON(mp) && !ip->i_udquot) {
error = xfs_qm_dqattach_one(ip, ip->i_d.di_uid, XFS_DQ_USER,
flags & XFS_QMOPT_DQALLOC,
NULL, &ip->i_udquot);
&ip->i_udquot);
if (error)
goto done;
nquotas++;
ASSERT(ip->i_udquot);
}
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (XFS_IS_GQUOTA_ON(mp)) {
if (XFS_IS_GQUOTA_ON(mp) && !ip->i_gdquot) {
error = xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
flags & XFS_QMOPT_DQALLOC,
ip->i_udquot, &ip->i_gdquot);
/*
* Don't worry about the udquot that we may have
* attached above. It'll get detached, if not already.
*/
&ip->i_gdquot);
if (error)
goto done;
nquotas++;
ASSERT(ip->i_gdquot);
}
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (XFS_IS_PQUOTA_ON(mp)) {
if (XFS_IS_PQUOTA_ON(mp) && !ip->i_pdquot) {
error = xfs_qm_dqattach_one(ip, xfs_get_projid(ip), XFS_DQ_PROJ,
flags & XFS_QMOPT_DQALLOC,
ip->i_udquot, &ip->i_pdquot);
/*
* Don't worry about the udquot that we may have
* attached above. It'll get detached, if not already.
*/
&ip->i_pdquot);
if (error)
goto done;
nquotas++;
ASSERT(ip->i_pdquot);
}
done:
/*
* Attach this group/project quota to the user quota as a hint.
* This WON'T, in general, result in a thrash.
* Don't worry about the dquots that we may have attached before any
* error - they'll get detached later if it has not already been done.
*/
if (nquotas > 1 && ip->i_udquot) {
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_gdquot || !XFS_IS_GQUOTA_ON(mp));
ASSERT(ip->i_pdquot || !XFS_IS_PQUOTA_ON(mp));
/*
* We do not have i_udquot locked at this point, but this check
* is OK since we don't depend on the i_gdquot to be accurate
* 100% all the time. It is just a hint, and this will
* succeed in general.
*/
if (ip->i_udquot->q_gdquot != ip->i_gdquot)
xfs_qm_dqattach_hint(ip, XFS_DQ_GROUP);
if (ip->i_udquot->q_pdquot != ip->i_pdquot)
xfs_qm_dqattach_hint(ip, XFS_DQ_PROJ);
}
done:
#ifdef DEBUG
if (!error) {
if (XFS_IS_UQUOTA_ON(mp))
ASSERT(ip->i_udquot);
if (XFS_IS_GQUOTA_ON(mp))
ASSERT(ip->i_gdquot);
if (XFS_IS_PQUOTA_ON(mp))
ASSERT(ip->i_pdquot);
}
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
#endif
return error;
}
@ -865,8 +693,7 @@ xfs_qm_init_quotainfo(
/* Precalc some constants */
qinf->qi_dqchunklen = XFS_FSB_TO_BB(mp, XFS_DQUOT_CLUSTER_SIZE_FSB);
qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(mp,
qinf->qi_dqchunklen);
qinf->qi_dqperchunk = xfs_calc_dquots_per_chunk(qinf->qi_dqchunklen);
mp->m_qflags |= (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_CHKD);

View file

@ -278,9 +278,10 @@ xfs_qm_scall_trunc_qfiles(
xfs_mount_t *mp,
uint flags)
{
int error;
int error = EINVAL;
if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0) {
if (!xfs_sb_version_hasquota(&mp->m_sb) || flags == 0 ||
(flags & ~XFS_DQ_ALLTYPES)) {
xfs_debug(mp, "%s: flags=%x m_qflags=%x",
__func__, flags, mp->m_qflags);
return XFS_ERROR(EINVAL);
@ -959,7 +960,6 @@ xfs_qm_export_flags(
STATIC int
xfs_dqrele_inode(
struct xfs_inode *ip,
struct xfs_perag *pag,
int flags,
void *args)
{

View file

@ -156,6 +156,6 @@ typedef __uint16_t xfs_qwarncnt_t;
extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq,
xfs_dqid_t id, uint type, uint flags, char *str);
extern int xfs_calc_dquots_per_chunk(struct xfs_mount *mp, unsigned int nbblks);
extern int xfs_calc_dquots_per_chunk(unsigned int nbblks);
#endif /* __XFS_QUOTA_H__ */

View file

@ -100,15 +100,35 @@ xfs_fs_set_xstate(
if (!XFS_IS_QUOTA_ON(mp))
return -EINVAL;
return -xfs_qm_scall_quotaoff(mp, flags);
case Q_XQUOTARM:
if (XFS_IS_QUOTA_ON(mp))
return -EINVAL;
return -xfs_qm_scall_trunc_qfiles(mp, flags);
}
return -EINVAL;
}
STATIC int
xfs_fs_rm_xquota(
struct super_block *sb,
unsigned int uflags)
{
struct xfs_mount *mp = XFS_M(sb);
unsigned int flags = 0;
if (sb->s_flags & MS_RDONLY)
return -EROFS;
if (XFS_IS_QUOTA_ON(mp))
return -EINVAL;
if (uflags & FS_USER_QUOTA)
flags |= XFS_DQ_USER;
if (uflags & FS_GROUP_QUOTA)
flags |= XFS_DQ_GROUP;
if (uflags & FS_USER_QUOTA)
flags |= XFS_DQ_PROJ;
return -xfs_qm_scall_trunc_qfiles(mp, flags);
}
STATIC int
xfs_fs_get_dqblk(
struct super_block *sb,
@ -149,6 +169,7 @@ const struct quotactl_ops xfs_quotactl_operations = {
.get_xstatev = xfs_fs_get_xstatev,
.get_xstate = xfs_fs_get_xstate,
.set_xstate = xfs_fs_set_xstate,
.rm_xquota = xfs_fs_rm_xquota,
.get_dqblk = xfs_fs_get_dqblk,
.set_dqblk = xfs_fs_set_dqblk,
};

View file

@ -74,7 +74,6 @@ xfs_rtbuf_get(
mp->m_bsize, 0, &bp, NULL);
if (error)
return error;
ASSERT(!xfs_buf_geterror(bp));
*bpp = bp;
return 0;
}

View file

@ -291,7 +291,8 @@ xfs_mount_validate_sb(
(sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) ||
sbp->sb_dblocks == 0 ||
sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) ||
sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp) ||
sbp->sb_shared_vn != 0)) {
xfs_notice(mp, "SB sanity check failed");
return XFS_ERROR(EFSCORRUPTED);
}
@ -333,15 +334,6 @@ xfs_mount_validate_sb(
xfs_warn(mp, "Offline file system operation in progress!");
return XFS_ERROR(EFSCORRUPTED);
}
/*
* Version 1 directory format has never worked on Linux.
*/
if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
xfs_warn(mp, "file system using version 1 directory format");
return XFS_ERROR(ENOSYS);
}
return 0;
}

View file

@ -36,8 +36,6 @@ struct xfs_trans;
#define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */
#define XFS_SB_VERSION_NUMBITS 0x000f
#define XFS_SB_VERSION_ALLFBITS 0xfff0
#define XFS_SB_VERSION_SASHFBITS 0xf000
#define XFS_SB_VERSION_REALFBITS 0x0ff0
#define XFS_SB_VERSION_ATTRBIT 0x0010
#define XFS_SB_VERSION_NLINKBIT 0x0020
#define XFS_SB_VERSION_QUOTABIT 0x0040
@ -50,24 +48,15 @@ struct xfs_trans;
#define XFS_SB_VERSION_DIRV2BIT 0x2000
#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */
#define XFS_SB_VERSION_MOREBITSBIT 0x8000
#define XFS_SB_VERSION_OKSASHFBITS \
(XFS_SB_VERSION_EXTFLGBIT | \
XFS_SB_VERSION_DIRV2BIT | \
XFS_SB_VERSION_BORGBIT)
#define XFS_SB_VERSION_OKREALFBITS \
(XFS_SB_VERSION_ATTRBIT | \
XFS_SB_VERSION_NLINKBIT | \
XFS_SB_VERSION_QUOTABIT | \
XFS_SB_VERSION_ALIGNBIT | \
XFS_SB_VERSION_DALIGNBIT | \
XFS_SB_VERSION_SHAREDBIT | \
XFS_SB_VERSION_LOGV2BIT | \
XFS_SB_VERSION_SECTORBIT | \
XFS_SB_VERSION_MOREBITSBIT)
#define XFS_SB_VERSION_OKREALBITS \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_OKREALFBITS | \
XFS_SB_VERSION_OKSASHFBITS)
/*
* Supported feature bit list is just all bits in the versionnum field because
* we've used them all up and understand them all. Except, of course, for the
* shared superblock bit, which nobody knows what it does and so is unsupported.
*/
#define XFS_SB_VERSION_OKBITS \
((XFS_SB_VERSION_NUMBITS | XFS_SB_VERSION_ALLFBITS) & \
~XFS_SB_VERSION_SHAREDBIT)
/*
* There are two words to hold XFS "feature" bits: the original
@ -76,7 +65,6 @@ struct xfs_trans;
*
* These defines represent bits in sb_features2.
*/
#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
@ -86,16 +74,11 @@ struct xfs_trans;
#define XFS_SB_VERSION2_CRCBIT 0x00000100 /* metadata CRCs */
#define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */
#define XFS_SB_VERSION2_OKREALFBITS \
#define XFS_SB_VERSION2_OKBITS \
(XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
XFS_SB_VERSION2_ATTR2BIT | \
XFS_SB_VERSION2_PROJID32BIT | \
XFS_SB_VERSION2_FTYPE)
#define XFS_SB_VERSION2_OKSASHFBITS \
(0)
#define XFS_SB_VERSION2_OKREALBITS \
(XFS_SB_VERSION2_OKREALFBITS | \
XFS_SB_VERSION2_OKSASHFBITS )
/*
* Superblock - in core version. Must match the ondisk version below.
@ -345,214 +328,140 @@ typedef enum {
#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
static inline int xfs_sb_good_version(xfs_sb_t *sbp)
/*
* The first XFS version we support is a v4 superblock with V2 directories.
*/
static inline bool xfs_sb_good_v4_features(struct xfs_sb *sbp)
{
/* We always support version 1-3 */
if (sbp->sb_versionnum >= XFS_SB_VERSION_1 &&
sbp->sb_versionnum <= XFS_SB_VERSION_3)
return 1;
if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT))
return false;
/* We support version 4 if all feature bits are supported */
if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) {
if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS) ||
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)))
return 0;
/* check for unknown features in the fs */
if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) ||
((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) &&
(sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS)))
return false;
if (sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
return 0;
return 1;
}
return true;
}
static inline bool xfs_sb_good_version(struct xfs_sb *sbp)
{
if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5)
return 1;
return 0;
return true;
if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4)
return xfs_sb_good_v4_features(sbp);
return false;
}
/*
* Detect a mismatched features2 field. Older kernels read/wrote
* this into the wrong slot, so to be safe we keep them in sync.
*/
static inline int xfs_sb_has_mismatched_features2(xfs_sb_t *sbp)
static inline bool xfs_sb_has_mismatched_features2(struct xfs_sb *sbp)
{
return (sbp->sb_bad_features2 != sbp->sb_features2);
return sbp->sb_bad_features2 != sbp->sb_features2;
}
static inline unsigned xfs_sb_version_tonew(unsigned v)
static inline bool xfs_sb_version_hasattr(struct xfs_sb *sbp)
{
if (v == XFS_SB_VERSION_1)
return XFS_SB_VERSION_4;
if (v == XFS_SB_VERSION_2)
return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
return XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT |
XFS_SB_VERSION_NLINKBIT;
return (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT);
}
static inline unsigned xfs_sb_version_toold(unsigned v)
static inline void xfs_sb_version_addattr(struct xfs_sb *sbp)
{
if (v & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT))
return 0;
if (v & XFS_SB_VERSION_NLINKBIT)
return XFS_SB_VERSION_3;
if (v & XFS_SB_VERSION_ATTRBIT)
return XFS_SB_VERSION_2;
return XFS_SB_VERSION_1;
sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
}
static inline int xfs_sb_version_hasattr(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasquota(struct xfs_sb *sbp)
{
return sbp->sb_versionnum == XFS_SB_VERSION_2 ||
sbp->sb_versionnum == XFS_SB_VERSION_3 ||
(XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT));
return (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
}
static inline void xfs_sb_version_addattr(xfs_sb_t *sbp)
static inline void xfs_sb_version_addquota(struct xfs_sb *sbp)
{
if (sbp->sb_versionnum == XFS_SB_VERSION_1)
sbp->sb_versionnum = XFS_SB_VERSION_2;
else if (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4)
sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT;
else
sbp->sb_versionnum = XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT;
sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
}
static inline int xfs_sb_version_hasnlink(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasalign(struct xfs_sb *sbp)
{
return sbp->sb_versionnum == XFS_SB_VERSION_3 ||
(XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_NLINKBIT));
}
static inline void xfs_sb_version_addnlink(xfs_sb_t *sbp)
{
if (sbp->sb_versionnum <= XFS_SB_VERSION_2)
sbp->sb_versionnum = XFS_SB_VERSION_3;
else
sbp->sb_versionnum |= XFS_SB_VERSION_NLINKBIT;
}
static inline int xfs_sb_version_hasquota(xfs_sb_t *sbp)
{
return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT);
}
static inline void xfs_sb_version_addquota(xfs_sb_t *sbp)
{
if (XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4)
sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT;
else
sbp->sb_versionnum = xfs_sb_version_tonew(sbp->sb_versionnum) |
XFS_SB_VERSION_QUOTABIT;
}
static inline int xfs_sb_version_hasalign(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 ||
(sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT));
}
static inline int xfs_sb_version_hasdalign(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasdalign(struct xfs_sb *sbp)
{
return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
return (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT);
}
static inline int xfs_sb_version_hasshared(xfs_sb_t *sbp)
static inline bool xfs_sb_version_haslogv2(struct xfs_sb *sbp)
{
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT);
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 ||
(sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT);
}
static inline int xfs_sb_version_hasdirv2(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasextflgbit(struct xfs_sb *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT));
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 ||
(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT);
}
static inline int xfs_sb_version_haslogv2(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hassector(struct xfs_sb *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT));
return (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
}
static inline int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasasciici(struct xfs_sb *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT));
return (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
}
static inline int xfs_sb_version_hassector(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasmorebits(struct xfs_sb *sbp)
{
return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT);
}
static inline int xfs_sb_version_hasasciici(xfs_sb_t *sbp)
{
return XFS_SB_VERSION_NUM(sbp) >= XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT);
}
static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 &&
(sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT));
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 ||
(sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT);
}
/*
* sb_features2 bit version macros.
*
* For example, for a bit defined as XFS_SB_VERSION2_FUNBIT, has a macro:
*
* SB_VERSION_HASFUNBIT(xfs_sb_t *sbp)
* ((xfs_sb_version_hasmorebits(sbp) &&
* ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT)
*/
static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
static inline bool xfs_sb_version_haslazysbcount(struct xfs_sb *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(xfs_sb_version_hasmorebits(sbp) &&
(sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT));
}
static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasattr2(struct xfs_sb *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(xfs_sb_version_hasmorebits(sbp) &&
(sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT));
}
static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
static inline void xfs_sb_version_addattr2(struct xfs_sb *sbp)
{
sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT;
sbp->sb_bad_features2 |= XFS_SB_VERSION2_ATTR2BIT;
}
static inline void xfs_sb_version_removeattr2(xfs_sb_t *sbp)
static inline void xfs_sb_version_removeattr2(struct xfs_sb *sbp)
{
sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT;
sbp->sb_bad_features2 &= ~XFS_SB_VERSION2_ATTR2BIT;
if (!sbp->sb_features2)
sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT;
}
static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
static inline bool xfs_sb_version_hasprojid32bit(struct xfs_sb *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) ||
(xfs_sb_version_hasmorebits(sbp) &&
(sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT));
}
static inline void xfs_sb_version_addprojid32bit(xfs_sb_t *sbp)
static inline void xfs_sb_version_addprojid32bit(struct xfs_sb *sbp)
{
sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT;
@ -587,7 +496,9 @@ xfs_sb_has_compat_feature(
return (sbp->sb_features_compat & feature) != 0;
}
#define XFS_SB_FEAT_RO_COMPAT_ALL 0
#define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */
#define XFS_SB_FEAT_RO_COMPAT_ALL \
(XFS_SB_FEAT_RO_COMPAT_FINOBT)
#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL
static inline bool
xfs_sb_has_ro_compat_feature(
@ -623,12 +534,12 @@ xfs_sb_has_incompat_log_feature(
/*
* V5 superblock specific feature checks
*/
static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp)
static inline int xfs_sb_version_hascrc(struct xfs_sb *sbp)
{
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
}
static inline int xfs_sb_version_has_pquotino(xfs_sb_t *sbp)
static inline int xfs_sb_version_has_pquotino(struct xfs_sb *sbp)
{
return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
}
@ -641,6 +552,12 @@ static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp)
(sbp->sb_features2 & XFS_SB_VERSION2_FTYPE));
}
static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp)
{
return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
(sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT);
}
/*
* end of superblock version macros
*/

View file

@ -238,7 +238,7 @@ int xfs_log_calc_minimum_size(struct xfs_mount *);
int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
uint32_t size, struct xfs_buf *bp);
bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset,
uint32_t size, struct xfs_buf *bp);
void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
struct xfs_inode *ip, struct xfs_ifork *ifp);

View file

@ -59,6 +59,7 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v)
{ "abtc2", XFSSTAT_END_ABTC_V2 },
{ "bmbt2", XFSSTAT_END_BMBT_V2 },
{ "ibt2", XFSSTAT_END_IBT_V2 },
{ "fibt2", XFSSTAT_END_FIBT_V2 },
/* we print both series of quota information together */
{ "qm", XFSSTAT_END_QM },
};

View file

@ -183,7 +183,23 @@ struct xfsstats {
__uint32_t xs_ibt_2_alloc;
__uint32_t xs_ibt_2_free;
__uint32_t xs_ibt_2_moves;
#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_IBT_V2+6)
#define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2+15)
__uint32_t xs_fibt_2_lookup;
__uint32_t xs_fibt_2_compare;
__uint32_t xs_fibt_2_insrec;
__uint32_t xs_fibt_2_delrec;
__uint32_t xs_fibt_2_newroot;
__uint32_t xs_fibt_2_killroot;
__uint32_t xs_fibt_2_increment;
__uint32_t xs_fibt_2_decrement;
__uint32_t xs_fibt_2_lshift;
__uint32_t xs_fibt_2_rshift;
__uint32_t xs_fibt_2_split;
__uint32_t xs_fibt_2_join;
__uint32_t xs_fibt_2_alloc;
__uint32_t xs_fibt_2_free;
__uint32_t xs_fibt_2_moves;
#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_FIBT_V2+6)
__uint32_t xs_qm_dqreclaims;
__uint32_t xs_qm_dqreclaim_misses;
__uint32_t xs_qm_dquot_dups;

View file

@ -765,20 +765,18 @@ xfs_open_devices(
* Setup xfs_mount buffer target pointers
*/
error = ENOMEM;
mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev, 0, mp->m_fsname);
mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev);
if (!mp->m_ddev_targp)
goto out_close_rtdev;
if (rtdev) {
mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev, 1,
mp->m_fsname);
mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev);
if (!mp->m_rtdev_targp)
goto out_free_ddev_targ;
}
if (logdev && logdev != ddev) {
mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev, 1,
mp->m_fsname);
mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev);
if (!mp->m_logdev_targp)
goto out_free_rtdev_targ;
} else {
@ -811,8 +809,7 @@ xfs_setup_devices(
{
int error;
error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_blocksize,
mp->m_sb.sb_sectsize);
error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize);
if (error)
return error;
@ -822,14 +819,12 @@ xfs_setup_devices(
if (xfs_sb_version_hassector(&mp->m_sb))
log_sector_size = mp->m_sb.sb_logsectsize;
error = xfs_setsize_buftarg(mp->m_logdev_targp,
mp->m_sb.sb_blocksize,
log_sector_size);
if (error)
return error;
}
if (mp->m_rtdev_targp) {
error = xfs_setsize_buftarg(mp->m_rtdev_targp,
mp->m_sb.sb_blocksize,
mp->m_sb.sb_sectsize);
if (error)
return error;
@ -1754,13 +1749,9 @@ init_xfs_fs(void)
if (error)
goto out_destroy_wq;
error = xfs_filestream_init();
if (error)
goto out_mru_cache_uninit;
error = xfs_buf_init();
if (error)
goto out_filestream_uninit;
goto out_mru_cache_uninit;
error = xfs_init_procfs();
if (error)
@ -1787,8 +1778,6 @@ init_xfs_fs(void)
xfs_cleanup_procfs();
out_buf_terminate:
xfs_buf_terminate();
out_filestream_uninit:
xfs_filestream_uninit();
out_mru_cache_uninit:
xfs_mru_cache_uninit();
out_destroy_wq:
@ -1807,7 +1796,6 @@ exit_xfs_fs(void)
xfs_sysctl_unregister();
xfs_cleanup_procfs();
xfs_buf_terminate();
xfs_filestream_uninit();
xfs_mru_cache_uninit();
xfs_destroy_workqueues();
xfs_destroy_zones();

View file

@ -27,6 +27,7 @@
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_dir2.h"
#include "xfs_inode.h"
#include "xfs_ialloc.h"
@ -92,7 +93,7 @@ xfs_readlink_bmap(
cur_chunk = bp->b_addr;
if (xfs_sb_version_hascrc(&mp->m_sb)) {
if (!xfs_symlink_hdr_ok(mp, ip->i_ino, offset,
if (!xfs_symlink_hdr_ok(ip->i_ino, offset,
byte_cnt, bp)) {
error = EFSCORRUPTED;
xfs_alert(mp,

View file

@ -80,7 +80,6 @@ xfs_symlink_hdr_set(
*/
bool
xfs_symlink_hdr_ok(
struct xfs_mount *mp,
xfs_ino_t ino,
uint32_t offset,
uint32_t size,

View file

@ -46,6 +46,7 @@
#include "xfs_log_recover.h"
#include "xfs_inode_item.h"
#include "xfs_bmap_btree.h"
#include "xfs_filestream.h"
/*
* We include this last to have the helpers above available for the trace

View file

@ -538,6 +538,64 @@ DEFINE_BUF_ITEM_EVENT(xfs_trans_bhold_release);
DEFINE_BUF_ITEM_EVENT(xfs_trans_binval);
DEFINE_BUF_ITEM_EVENT(xfs_trans_buf_ordered);
DECLARE_EVENT_CLASS(xfs_filestream_class,
TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno),
TP_ARGS(ip, agno),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(xfs_agnumber_t, agno)
__field(int, streams)
),
TP_fast_assign(
__entry->dev = VFS_I(ip)->i_sb->s_dev;
__entry->ino = ip->i_ino;
__entry->agno = agno;
__entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno);
),
TP_printk("dev %d:%d ino 0x%llx agno %u streams %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->agno,
__entry->streams)
)
#define DEFINE_FILESTREAM_EVENT(name) \
DEFINE_EVENT(xfs_filestream_class, name, \
TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno), \
TP_ARGS(ip, agno))
DEFINE_FILESTREAM_EVENT(xfs_filestream_free);
DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup);
DEFINE_FILESTREAM_EVENT(xfs_filestream_scan);
TRACE_EVENT(xfs_filestream_pick,
TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno,
xfs_extlen_t free, int nscan),
TP_ARGS(ip, agno, free, nscan),
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_ino_t, ino)
__field(xfs_agnumber_t, agno)
__field(int, streams)
__field(xfs_extlen_t, free)
__field(int, nscan)
),
TP_fast_assign(
__entry->dev = VFS_I(ip)->i_sb->s_dev;
__entry->ino = ip->i_ino;
__entry->agno = agno;
__entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno);
__entry->free = free;
__entry->nscan = nscan;
),
TP_printk("dev %d:%d ino 0x%llx agno %u streams %d free %d nscan %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->ino,
__entry->agno,
__entry->streams,
__entry->free,
__entry->nscan)
);
DECLARE_EVENT_CLASS(xfs_lock_class,
TP_PROTO(struct xfs_inode *ip, unsigned lock_flags,
unsigned long caller_ip),

View file

@ -827,7 +827,7 @@ xfs_trans_committed_bulk(
xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn);
spin_lock(&ailp->xa_lock);
xfs_trans_ail_cursor_done(ailp, &cur);
xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock);
}

View file

@ -173,7 +173,6 @@ xfs_trans_ail_cursor_next(
*/
void
xfs_trans_ail_cursor_done(
struct xfs_ail *ailp,
struct xfs_ail_cursor *cur)
{
cur->item = NULL;
@ -368,7 +367,7 @@ xfsaild_push(
* If the AIL is empty or our push has reached the end we are
* done now.
*/
xfs_trans_ail_cursor_done(ailp, &cur);
xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock);
goto out_done;
}
@ -453,7 +452,7 @@ xfsaild_push(
break;
lsn = lip->li_lsn;
}
xfs_trans_ail_cursor_done(ailp, &cur);
xfs_trans_ail_cursor_done(&cur);
spin_unlock(&ailp->xa_lock);
if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list))

View file

@ -133,8 +133,7 @@ struct xfs_log_item * xfs_trans_ail_cursor_last(struct xfs_ail *ailp,
xfs_lsn_t lsn);
struct xfs_log_item * xfs_trans_ail_cursor_next(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur);
void xfs_trans_ail_cursor_done(struct xfs_ail *ailp,
struct xfs_ail_cursor *cur);
void xfs_trans_ail_cursor_done(struct xfs_ail_cursor *cur);
#if BITS_PER_LONG != 64
static inline void

View file

@ -26,6 +26,7 @@
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_da_format.h"
#include "xfs_da_btree.h"
#include "xfs_inode.h"
#include "xfs_bmap_btree.h"
#include "xfs_ialloc.h"
@ -105,6 +106,47 @@ xfs_calc_inode_res(
2 * XFS_BMBT_BLOCK_LEN(mp));
}
/*
* The free inode btree is a conditional feature and the log reservation
* requirements differ slightly from that of the traditional inode allocation
* btree. The finobt tracks records for inode chunks with at least one free
* inode. A record can be removed from the tree for an inode allocation
* or free and thus the finobt reservation is unconditional across:
*
* - inode allocation
* - inode free
* - inode chunk allocation
*
* The 'modify' param indicates to include the record modification scenario. The
* 'alloc' param indicates to include the reservation for free space btree
* modifications on behalf of finobt modifications. This is required only for
* transactions that do not already account for free space btree modifications.
*
* the free inode btree: max depth * block size
* the allocation btrees: 2 trees * (max depth - 1) * block size
* the free inode btree entry: block size
*/
STATIC uint
xfs_calc_finobt_res(
struct xfs_mount *mp,
int alloc,
int modify)
{
uint res;
if (!xfs_sb_version_hasfinobt(&mp->m_sb))
return 0;
res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
if (alloc)
res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1));
if (modify)
res += (uint)XFS_FSB_TO_B(mp, 1);
return res;
}
/*
* Various log reservation values.
*
@ -302,6 +344,7 @@ xfs_calc_remove_reservation(
* the superblock for the nlink flag: sector size
* the directory btree: (max depth + v2) * dir block size
* the directory inode's bmap btree: (max depth + v2) * block size
* the finobt (record modification and allocation btrees)
*/
STATIC uint
xfs_calc_create_resv_modify(
@ -310,7 +353,8 @@ xfs_calc_create_resv_modify(
return xfs_calc_inode_res(mp, 2) +
xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
(uint)XFS_FSB_TO_B(mp, 1) +
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 1, 1);
}
/*
@ -348,6 +392,7 @@ __xfs_calc_create_reservation(
* the superblock for the nlink flag: sector size
* the inode btree: max depth * blocksize
* the allocation btrees: 2 trees * (max depth - 1) * block size
* the finobt (record insertion)
*/
STATIC uint
xfs_calc_icreate_resv_alloc(
@ -357,7 +402,8 @@ xfs_calc_icreate_resv_alloc(
mp->m_sb.sb_sectsize +
xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1));
XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 0, 0);
}
STATIC uint
@ -425,6 +471,7 @@ xfs_calc_symlink_reservation(
* the on disk inode before ours in the agi hash list: inode cluster size
* the inode btree: max depth * blocksize
* the allocation btrees: 2 trees * (max depth - 1) * block size
* the finobt (record insertion, removal or modification)
*/
STATIC uint
xfs_calc_ifree_reservation(
@ -439,7 +486,8 @@ xfs_calc_ifree_reservation(
xfs_calc_buf_res(2 + mp->m_ialloc_blks +
mp->m_in_maxlevels, 0) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1));
XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 0, 1);
}
/*
@ -562,7 +610,7 @@ xfs_calc_addafork_reservation(
return XFS_DQUOT_LOGRES(mp) +
xfs_calc_inode_res(mp, 1) +
xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
xfs_calc_buf_res(1, mp->m_dirblksize) +
xfs_calc_buf_res(1, mp->m_dir_geo->blksize) +
xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1,
XFS_FSB_TO_B(mp, 1)) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),

View file

@ -28,7 +28,8 @@
(((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \
XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \
XFS_EXTENTADD_SPACE_RES(mp,w))
#define XFS_DAENTER_1B(mp,w) ((w) == XFS_DATA_FORK ? (mp)->m_dirblkfsbs : 1)
#define XFS_DAENTER_1B(mp,w) \
((w) == XFS_DATA_FORK ? (mp)->m_dir_geo->fsbcount : 1)
#define XFS_DAENTER_DBS(mp,w) \
(XFS_DA_NODE_MAXDEPTH + (((w) == XFS_DATA_FORK) ? 2 : 0))
#define XFS_DAENTER_BLOCKS(mp,w) \
@ -47,13 +48,15 @@
#define XFS_DIRREMOVE_SPACE_RES(mp) \
XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
#define XFS_IALLOC_SPACE_RES(mp) \
((mp)->m_ialloc_blks + (mp)->m_in_maxlevels - 1)
((mp)->m_ialloc_blks + \
(xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
((mp)->m_in_maxlevels - 1)))
/*
* Space reservation values for various transactions.
*/
#define XFS_ADDAFORK_SPACE_RES(mp) \
((mp)->m_dirblkfsbs + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))
((mp)->m_dir_geo->fsbcount + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK))
#define XFS_ATTRRM_SPACE_RES(mp) \
XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK)
/* This macro is not used - see inline code in xfs_attr_set */
@ -82,5 +85,8 @@
(XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \
(XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
#define XFS_IFREE_SPACE_RES(mp) \
(xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
#endif /* __XFS_TRANS_SPACE_H__ */

View file

@ -134,7 +134,7 @@ typedef enum {
typedef enum {
XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
XFS_BTNUM_MAX
XFS_BTNUM_FINOi, XFS_BTNUM_MAX
} xfs_btnum_t;
struct xfs_name {

View file

@ -329,6 +329,7 @@ struct quotactl_ops {
int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
int (*set_xstate)(struct super_block *, unsigned int, int);
int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
int (*rm_xquota)(struct super_block *, unsigned int);
};
struct quota_format_type {