aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r--fs/xfs/xfs_bmap.c84
1 files changed, 66 insertions, 18 deletions
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 26645d267f1b..3e013530d00d 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. 2 * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved.
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify it 4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as 5 * under the terms of version 2 of the GNU General Public License as
@@ -62,6 +62,7 @@
62#include "xfs_error.h" 62#include "xfs_error.h"
63#include "xfs_da_btree.h" 63#include "xfs_da_btree.h"
64#include "xfs_dir_leaf.h" 64#include "xfs_dir_leaf.h"
65#include "xfs_attr_leaf.h"
65#include "xfs_bit.h" 66#include "xfs_bit.h"
66#include "xfs_rw.h" 67#include "xfs_rw.h"
67#include "xfs_quota.h" 68#include "xfs_quota.h"
@@ -3337,6 +3338,29 @@ xfs_bmap_insert_exlist(
3337} 3338}
3338 3339
3339/* 3340/*
3341 * Helper routine to reset inode di_forkoff field when switching
3342 * attribute fork from local to extent format - we reset it where
3343 * possible to make space available for inline data fork extents.
3344 */
3345STATIC void
3346xfs_bmap_forkoff_reset(
3347 xfs_mount_t *mp,
3348 xfs_inode_t *ip,
3349 int whichfork)
3350{
3351 if (whichfork == XFS_ATTR_FORK &&
3352 (ip->i_d.di_format != XFS_DINODE_FMT_DEV) &&
3353 (ip->i_d.di_format != XFS_DINODE_FMT_UUID) &&
3354 ((mp->m_attroffset >> 3) > ip->i_d.di_forkoff)) {
3355 ip->i_d.di_forkoff = mp->m_attroffset >> 3;
3356 ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) /
3357 (uint)sizeof(xfs_bmbt_rec_t);
3358 ip->i_afp->if_ext_max = XFS_IFORK_ASIZE(ip) /
3359 (uint)sizeof(xfs_bmbt_rec_t);
3360 }
3361}
3362
3363/*
3340 * Convert a local file to an extents file. 3364 * Convert a local file to an extents file.
3341 * This code is out of bounds for data forks of regular files, 3365 * This code is out of bounds for data forks of regular files,
3342 * since the file data needs to get logged so things will stay consistent. 3366 * since the file data needs to get logged so things will stay consistent.
@@ -3403,6 +3427,7 @@ xfs_bmap_local_to_extents(
3403 memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data, 3427 memcpy((char *)XFS_BUF_PTR(bp), ifp->if_u1.if_data,
3404 ifp->if_bytes); 3428 ifp->if_bytes);
3405 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); 3429 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
3430 xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
3406 xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); 3431 xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
3407 xfs_iext_realloc(ip, 1, whichfork); 3432 xfs_iext_realloc(ip, 1, whichfork);
3408 ep = ifp->if_u1.if_extents; 3433 ep = ifp->if_u1.if_extents;
@@ -3413,8 +3438,10 @@ xfs_bmap_local_to_extents(
3413 XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip, 3438 XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
3414 XFS_TRANS_DQ_BCOUNT, 1L); 3439 XFS_TRANS_DQ_BCOUNT, 1L);
3415 flags |= XFS_ILOG_FEXT(whichfork); 3440 flags |= XFS_ILOG_FEXT(whichfork);
3416 } else 3441 } else {
3417 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); 3442 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
3443 xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
3444 }
3418 ifp->if_flags &= ~XFS_IFINLINE; 3445 ifp->if_flags &= ~XFS_IFINLINE;
3419 ifp->if_flags |= XFS_IFEXTENTS; 3446 ifp->if_flags |= XFS_IFEXTENTS;
3420 XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); 3447 XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
@@ -3796,22 +3823,24 @@ xfs_bunmap_trace(
3796int /* error code */ 3823int /* error code */
3797xfs_bmap_add_attrfork( 3824xfs_bmap_add_attrfork(
3798 xfs_inode_t *ip, /* incore inode pointer */ 3825 xfs_inode_t *ip, /* incore inode pointer */
3799 int rsvd) /* OK to allocated reserved blocks in trans */ 3826 int size, /* space new attribute needs */
3827 int rsvd) /* xact may use reserved blks */
3800{ 3828{
3801 int blks; /* space reservation */
3802 int committed; /* xaction was committed */
3803 int error; /* error return value */
3804 xfs_fsblock_t firstblock; /* 1st block/ag allocated */ 3829 xfs_fsblock_t firstblock; /* 1st block/ag allocated */
3805 xfs_bmap_free_t flist; /* freed extent list */ 3830 xfs_bmap_free_t flist; /* freed extent list */
3806 int logflags; /* logging flags */
3807 xfs_mount_t *mp; /* mount structure */ 3831 xfs_mount_t *mp; /* mount structure */
3808 unsigned long s; /* spinlock spl value */
3809 xfs_trans_t *tp; /* transaction pointer */ 3832 xfs_trans_t *tp; /* transaction pointer */
3833 unsigned long s; /* spinlock spl value */
3834 int blks; /* space reservation */
3835 int version = 1; /* superblock attr version */
3836 int committed; /* xaction was committed */
3837 int logflags; /* logging flags */
3838 int error; /* error return value */
3810 3839
3840 ASSERT(XFS_IFORK_Q(ip) == 0);
3811 ASSERT(ip->i_df.if_ext_max == 3841 ASSERT(ip->i_df.if_ext_max ==
3812 XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t)); 3842 XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
3813 if (XFS_IFORK_Q(ip)) 3843
3814 return 0;
3815 mp = ip->i_mount; 3844 mp = ip->i_mount;
3816 ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); 3845 ASSERT(!XFS_NOT_DQATTACHED(mp, ip));
3817 tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK); 3846 tp = xfs_trans_alloc(mp, XFS_TRANS_ADDAFORK);
@@ -3853,7 +3882,11 @@ xfs_bmap_add_attrfork(
3853 case XFS_DINODE_FMT_LOCAL: 3882 case XFS_DINODE_FMT_LOCAL:
3854 case XFS_DINODE_FMT_EXTENTS: 3883 case XFS_DINODE_FMT_EXTENTS:
3855 case XFS_DINODE_FMT_BTREE: 3884 case XFS_DINODE_FMT_BTREE:
3856 ip->i_d.di_forkoff = mp->m_attroffset >> 3; 3885 ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size);
3886 if (!ip->i_d.di_forkoff)
3887 ip->i_d.di_forkoff = mp->m_attroffset >> 3;
3888 else if (!(mp->m_flags & XFS_MOUNT_COMPAT_ATTR))
3889 version = 2;
3857 break; 3890 break;
3858 default: 3891 default:
3859 ASSERT(0); 3892 ASSERT(0);
@@ -3890,12 +3923,21 @@ xfs_bmap_add_attrfork(
3890 xfs_trans_log_inode(tp, ip, logflags); 3923 xfs_trans_log_inode(tp, ip, logflags);
3891 if (error) 3924 if (error)
3892 goto error2; 3925 goto error2;
3893 if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { 3926 if (!XFS_SB_VERSION_HASATTR(&mp->m_sb) ||
3927 (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2)) {
3928 logflags = 0;
3894 s = XFS_SB_LOCK(mp); 3929 s = XFS_SB_LOCK(mp);
3895 if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) { 3930 if (!XFS_SB_VERSION_HASATTR(&mp->m_sb)) {
3896 XFS_SB_VERSION_ADDATTR(&mp->m_sb); 3931 XFS_SB_VERSION_ADDATTR(&mp->m_sb);
3932 logflags |= XFS_SB_VERSIONNUM;
3933 }
3934 if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb) && version == 2) {
3935 XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
3936 logflags |= (XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
3937 }
3938 if (logflags) {
3897 XFS_SB_UNLOCK(mp, s); 3939 XFS_SB_UNLOCK(mp, s);
3898 xfs_mod_sb(tp, XFS_SB_VERSIONNUM); 3940 xfs_mod_sb(tp, logflags);
3899 } else 3941 } else
3900 XFS_SB_UNLOCK(mp, s); 3942 XFS_SB_UNLOCK(mp, s);
3901 } 3943 }
@@ -3988,13 +4030,19 @@ xfs_bmap_compute_maxlevels(
3988 * (a signed 32-bit number, xfs_extnum_t), or by di_anextents 4030 * (a signed 32-bit number, xfs_extnum_t), or by di_anextents
3989 * (a signed 16-bit number, xfs_aextnum_t). 4031 * (a signed 16-bit number, xfs_aextnum_t).
3990 */ 4032 */
3991 maxleafents = (whichfork == XFS_DATA_FORK) ? MAXEXTNUM : MAXAEXTNUM; 4033 if (whichfork == XFS_DATA_FORK) {
4034 maxleafents = MAXEXTNUM;
4035 sz = (mp->m_flags & XFS_MOUNT_COMPAT_ATTR) ?
4036 mp->m_attroffset : XFS_BMDR_SPACE_CALC(MINDBTPTRS);
4037 } else {
4038 maxleafents = MAXAEXTNUM;
4039 sz = (mp->m_flags & XFS_MOUNT_COMPAT_ATTR) ?
4040 mp->m_sb.sb_inodesize - mp->m_attroffset :
4041 XFS_BMDR_SPACE_CALC(MINABTPTRS);
4042 }
4043 maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0);
3992 minleafrecs = mp->m_bmap_dmnr[0]; 4044 minleafrecs = mp->m_bmap_dmnr[0];
3993 minnoderecs = mp->m_bmap_dmnr[1]; 4045 minnoderecs = mp->m_bmap_dmnr[1];
3994 sz = (whichfork == XFS_DATA_FORK) ?
3995 mp->m_attroffset :
3996 mp->m_sb.sb_inodesize - mp->m_attroffset;
3997 maxrootrecs = (int)XFS_BTREE_BLOCK_MAXRECS(sz, xfs_bmdr, 0);
3998 maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; 4046 maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs;
3999 for (level = 1; maxblocks > 1; level++) { 4047 for (level = 1; maxblocks > 1; level++) {
4000 if (maxblocks <= maxrootrecs) 4048 if (maxblocks <= maxrootrecs)