diff options
Diffstat (limited to 'fs/xfs/xfs_bmap.c')
-rw-r--r-- | fs/xfs/xfs_bmap.c | 84 |
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 | */ | ||
3345 | STATIC void | ||
3346 | xfs_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( | |||
3796 | int /* error code */ | 3823 | int /* error code */ |
3797 | xfs_bmap_add_attrfork( | 3824 | xfs_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) |