aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_attr_leaf.c2
-rw-r--r--fs/xfs/xfs_bmap.c199
-rw-r--r--fs/xfs/xfs_bmap.h1
-rw-r--r--fs/xfs/xfs_dir2_block.c20
4 files changed, 98 insertions, 124 deletions
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 31d3cd129269..b800fbcafc7f 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -690,6 +690,8 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
690 sf = (xfs_attr_shortform_t *)tmpbuffer; 690 sf = (xfs_attr_shortform_t *)tmpbuffer;
691 691
692 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); 692 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
693 xfs_bmap_local_to_extents_empty(dp, XFS_ATTR_FORK);
694
693 bp = NULL; 695 bp = NULL;
694 error = xfs_da_grow_inode(args, &blkno); 696 error = xfs_da_grow_inode(args, &blkno);
695 if (error) { 697 if (error) {
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 89042848f9ec..05c698ccb238 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -1161,6 +1161,24 @@ xfs_bmap_extents_to_btree(
1161 * since the file data needs to get logged so things will stay consistent. 1161 * since the file data needs to get logged so things will stay consistent.
1162 * (The bmap-level manipulations are ok, though). 1162 * (The bmap-level manipulations are ok, though).
1163 */ 1163 */
1164void
1165xfs_bmap_local_to_extents_empty(
1166 struct xfs_inode *ip,
1167 int whichfork)
1168{
1169 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
1170
1171 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
1172 ASSERT(ifp->if_bytes == 0);
1173 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0);
1174
1175 xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork);
1176 ifp->if_flags &= ~XFS_IFINLINE;
1177 ifp->if_flags |= XFS_IFEXTENTS;
1178 XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS);
1179}
1180
1181
1164STATIC int /* error */ 1182STATIC int /* error */
1165xfs_bmap_local_to_extents( 1183xfs_bmap_local_to_extents(
1166 xfs_trans_t *tp, /* transaction pointer */ 1184 xfs_trans_t *tp, /* transaction pointer */
@@ -1174,9 +1192,12 @@ xfs_bmap_local_to_extents(
1174 struct xfs_inode *ip, 1192 struct xfs_inode *ip,
1175 struct xfs_ifork *ifp)) 1193 struct xfs_ifork *ifp))
1176{ 1194{
1177 int error; /* error return value */ 1195 int error = 0;
1178 int flags; /* logging flags returned */ 1196 int flags; /* logging flags returned */
1179 xfs_ifork_t *ifp; /* inode fork pointer */ 1197 xfs_ifork_t *ifp; /* inode fork pointer */
1198 xfs_alloc_arg_t args; /* allocation arguments */
1199 xfs_buf_t *bp; /* buffer for extent block */
1200 xfs_bmbt_rec_host_t *ep; /* extent record pointer */
1180 1201
1181 /* 1202 /*
1182 * We don't want to deal with the case of keeping inode data inline yet. 1203 * We don't want to deal with the case of keeping inode data inline yet.
@@ -1185,68 +1206,65 @@ xfs_bmap_local_to_extents(
1185 ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK)); 1206 ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK));
1186 ifp = XFS_IFORK_PTR(ip, whichfork); 1207 ifp = XFS_IFORK_PTR(ip, whichfork);
1187 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); 1208 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL);
1209
1210 if (!ifp->if_bytes) {
1211 xfs_bmap_local_to_extents_empty(ip, whichfork);
1212 flags = XFS_ILOG_CORE;
1213 goto done;
1214 }
1215
1188 flags = 0; 1216 flags = 0;
1189 error = 0; 1217 error = 0;
1190 if (ifp->if_bytes) { 1218 ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) ==
1191 xfs_alloc_arg_t args; /* allocation arguments */ 1219 XFS_IFINLINE);
1192 xfs_buf_t *bp; /* buffer for extent block */ 1220 memset(&args, 0, sizeof(args));
1193 xfs_bmbt_rec_host_t *ep;/* extent record pointer */ 1221 args.tp = tp;
1194 1222 args.mp = ip->i_mount;
1195 ASSERT((ifp->if_flags & 1223 args.firstblock = *firstblock;
1196 (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == XFS_IFINLINE); 1224 /*
1197 memset(&args, 0, sizeof(args)); 1225 * Allocate a block. We know we need only one, since the
1198 args.tp = tp; 1226 * file currently fits in an inode.
1199 args.mp = ip->i_mount; 1227 */
1200 args.firstblock = *firstblock; 1228 if (*firstblock == NULLFSBLOCK) {
1201 /* 1229 args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
1202 * Allocate a block. We know we need only one, since the 1230 args.type = XFS_ALLOCTYPE_START_BNO;
1203 * file currently fits in an inode.
1204 */
1205 if (*firstblock == NULLFSBLOCK) {
1206 args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino);
1207 args.type = XFS_ALLOCTYPE_START_BNO;
1208 } else {
1209 args.fsbno = *firstblock;
1210 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1211 }
1212 args.total = total;
1213 args.minlen = args.maxlen = args.prod = 1;
1214 error = xfs_alloc_vextent(&args);
1215 if (error)
1216 goto done;
1217
1218 /* Can't fail, the space was reserved. */
1219 ASSERT(args.fsbno != NULLFSBLOCK);
1220 ASSERT(args.len == 1);
1221 *firstblock = args.fsbno;
1222 bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
1223
1224 /* initialise the block and copy the data */
1225 init_fn(tp, bp, ip, ifp);
1226
1227 /* account for the change in fork size and log everything */
1228 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
1229 xfs_bmap_forkoff_reset(args.mp, ip, whichfork);
1230 xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
1231 xfs_iext_add(ifp, 0, 1);
1232 ep = xfs_iext_get_ext(ifp, 0);
1233 xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
1234 trace_xfs_bmap_post_update(ip, 0,
1235 whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0,
1236 _THIS_IP_);
1237 XFS_IFORK_NEXT_SET(ip, whichfork, 1);
1238 ip->i_d.di_nblocks = 1;
1239 xfs_trans_mod_dquot_byino(tp, ip,
1240 XFS_TRANS_DQ_BCOUNT, 1L);
1241 flags |= xfs_ilog_fext(whichfork);
1242 } else { 1231 } else {
1243 ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); 1232 args.fsbno = *firstblock;
1244 xfs_bmap_forkoff_reset(ip->i_mount, ip, whichfork); 1233 args.type = XFS_ALLOCTYPE_NEAR_BNO;
1245 } 1234 }
1246 ifp->if_flags &= ~XFS_IFINLINE; 1235 args.total = total;
1247 ifp->if_flags |= XFS_IFEXTENTS; 1236 args.minlen = args.maxlen = args.prod = 1;
1248 XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); 1237 error = xfs_alloc_vextent(&args);
1238 if (error)
1239 goto done;
1240
1241 /* Can't fail, the space was reserved. */
1242 ASSERT(args.fsbno != NULLFSBLOCK);
1243 ASSERT(args.len == 1);
1244 *firstblock = args.fsbno;
1245 bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
1246
1247 /* initialise the block and copy the data */
1248 init_fn(tp, bp, ip, ifp);
1249
1250 /* account for the change in fork size and log everything */
1251 xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
1252 xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
1253 xfs_bmap_local_to_extents_empty(ip, whichfork);
1249 flags |= XFS_ILOG_CORE; 1254 flags |= XFS_ILOG_CORE;
1255
1256 xfs_iext_add(ifp, 0, 1);
1257 ep = xfs_iext_get_ext(ifp, 0);
1258 xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
1259 trace_xfs_bmap_post_update(ip, 0,
1260 whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0,
1261 _THIS_IP_);
1262 XFS_IFORK_NEXT_SET(ip, whichfork, 1);
1263 ip->i_d.di_nblocks = 1;
1264 xfs_trans_mod_dquot_byino(tp, ip,
1265 XFS_TRANS_DQ_BCOUNT, 1L);
1266 flags |= xfs_ilog_fext(whichfork);
1267
1250done: 1268done:
1251 *logflagsp = flags; 1269 *logflagsp = flags;
1252 return error; 1270 return error;
@@ -1323,25 +1341,6 @@ xfs_bmap_add_attrfork_extents(
1323} 1341}
1324 1342
1325/* 1343/*
1326 * Block initialisation function for local to extent format conversion.
1327 *
1328 * This shouldn't actually be called by anyone, so make sure debug kernels cause
1329 * a noticable failure.
1330 */
1331STATIC void
1332xfs_bmap_local_to_extents_init_fn(
1333 struct xfs_trans *tp,
1334 struct xfs_buf *bp,
1335 struct xfs_inode *ip,
1336 struct xfs_ifork *ifp)
1337{
1338 ASSERT(0);
1339 bp->b_ops = &xfs_bmbt_buf_ops;
1340 memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
1341 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_BTREE_BUF);
1342}
1343
1344/*
1345 * Called from xfs_bmap_add_attrfork to handle local format files. Each 1344 * Called from xfs_bmap_add_attrfork to handle local format files. Each
1346 * different data fork content type needs a different callout to do the 1345 * different data fork content type needs a different callout to do the
1347 * conversion. Some are basic and only require special block initialisation 1346 * conversion. Some are basic and only require special block initialisation
@@ -1381,9 +1380,9 @@ xfs_bmap_add_attrfork_local(
1381 flags, XFS_DATA_FORK, 1380 flags, XFS_DATA_FORK,
1382 xfs_symlink_local_to_remote); 1381 xfs_symlink_local_to_remote);
1383 1382
1384 return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, flags, 1383 /* should only be called for types that support local format data */
1385 XFS_DATA_FORK, 1384 ASSERT(0);
1386 xfs_bmap_local_to_extents_init_fn); 1385 return EFSCORRUPTED;
1387} 1386}
1388 1387
1389/* 1388/*
@@ -4907,20 +4906,19 @@ xfs_bmapi_write(
4907 orig_mval = mval; 4906 orig_mval = mval;
4908 orig_nmap = *nmap; 4907 orig_nmap = *nmap;
4909#endif 4908#endif
4909 whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
4910 XFS_ATTR_FORK : XFS_DATA_FORK;
4910 4911
4911 ASSERT(*nmap >= 1); 4912 ASSERT(*nmap >= 1);
4912 ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); 4913 ASSERT(*nmap <= XFS_BMAP_MAX_NMAP);
4913 ASSERT(!(flags & XFS_BMAPI_IGSTATE)); 4914 ASSERT(!(flags & XFS_BMAPI_IGSTATE));
4914 ASSERT(tp != NULL); 4915 ASSERT(tp != NULL);
4915 ASSERT(len > 0); 4916 ASSERT(len > 0);
4916 4917 ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
4917 whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
4918 XFS_ATTR_FORK : XFS_DATA_FORK;
4919 4918
4920 if (unlikely(XFS_TEST_ERROR( 4919 if (unlikely(XFS_TEST_ERROR(
4921 (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && 4920 (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
4922 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && 4921 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
4923 XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL),
4924 mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { 4922 mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) {
4925 XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp); 4923 XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp);
4926 return XFS_ERROR(EFSCORRUPTED); 4924 return XFS_ERROR(EFSCORRUPTED);
@@ -4933,37 +4931,6 @@ xfs_bmapi_write(
4933 4931
4934 XFS_STATS_INC(xs_blk_mapw); 4932 XFS_STATS_INC(xs_blk_mapw);
4935 4933
4936 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
4937 /*
4938 * XXX (dgc): This assumes we are only called for inodes that
4939 * contain content neutral data in local format. Anything that
4940 * contains caller-specific data in local format that needs
4941 * transformation to move to a block format needs to do the
4942 * conversion to extent format itself.
4943 *
4944 * Directory data forks and attribute forks handle this
4945 * themselves, but with the addition of metadata verifiers every
4946 * data fork in local format now contains caller specific data
4947 * and as such conversion through this function is likely to be
4948 * broken.
4949 *
4950 * The only likely user of this branch is for remote symlinks,
4951 * but we cannot overwrite the data fork contents of the symlink
4952 * (EEXIST occurs higher up the stack) and so it will never go
4953 * from local format to extent format here. Hence I don't think
4954 * this branch is ever executed intentionally and we should
4955 * consider removing it and asserting that xfs_bmapi_write()
4956 * cannot be called directly on local format forks. i.e. callers
4957 * are completely responsible for local to extent format
4958 * conversion, not xfs_bmapi_write().
4959 */
4960 error = xfs_bmap_local_to_extents(tp, ip, firstblock, total,
4961 &bma.logflags, whichfork,
4962 xfs_bmap_local_to_extents_init_fn);
4963 if (error)
4964 goto error0;
4965 }
4966
4967 if (*firstblock == NULLFSBLOCK) { 4934 if (*firstblock == NULLFSBLOCK) {
4968 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) 4935 if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
4969 bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1; 4936 bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1;
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 5f469c3516eb..1cf1292d29b7 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -172,6 +172,7 @@ void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
172#endif 172#endif
173 173
174int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); 174int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd);
175void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork);
175void xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len, 176void xfs_bmap_add_free(xfs_fsblock_t bno, xfs_filblks_t len,
176 struct xfs_bmap_free *flist, struct xfs_mount *mp); 177 struct xfs_bmap_free *flist, struct xfs_mount *mp);
177void xfs_bmap_cancel(struct xfs_bmap_free *flist); 178void xfs_bmap_cancel(struct xfs_bmap_free *flist);
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index e59f5fc816fe..53b9aa26d567 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -29,6 +29,7 @@
29#include "xfs_dinode.h" 29#include "xfs_dinode.h"
30#include "xfs_inode.h" 30#include "xfs_inode.h"
31#include "xfs_inode_item.h" 31#include "xfs_inode_item.h"
32#include "xfs_bmap.h"
32#include "xfs_buf_item.h" 33#include "xfs_buf_item.h"
33#include "xfs_dir2.h" 34#include "xfs_dir2.h"
34#include "xfs_dir2_format.h" 35#include "xfs_dir2_format.h"
@@ -1167,13 +1168,15 @@ xfs_dir2_sf_to_block(
1167 __be16 *tagp; /* end of data entry */ 1168 __be16 *tagp; /* end of data entry */
1168 xfs_trans_t *tp; /* transaction pointer */ 1169 xfs_trans_t *tp; /* transaction pointer */
1169 struct xfs_name name; 1170 struct xfs_name name;
1171 struct xfs_ifork *ifp;
1170 1172
1171 trace_xfs_dir2_sf_to_block(args); 1173 trace_xfs_dir2_sf_to_block(args);
1172 1174
1173 dp = args->dp; 1175 dp = args->dp;
1174 tp = args->trans; 1176 tp = args->trans;
1175 mp = dp->i_mount; 1177 mp = dp->i_mount;
1176 ASSERT(dp->i_df.if_flags & XFS_IFINLINE); 1178 ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK);
1179 ASSERT(ifp->if_flags & XFS_IFINLINE);
1177 /* 1180 /*
1178 * Bomb out if the shortform directory is way too short. 1181 * Bomb out if the shortform directory is way too short.
1179 */ 1182 */
@@ -1182,22 +1185,23 @@ xfs_dir2_sf_to_block(
1182 return XFS_ERROR(EIO); 1185 return XFS_ERROR(EIO);
1183 } 1186 }
1184 1187
1185 oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; 1188 oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data;
1186 1189
1187 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); 1190 ASSERT(ifp->if_bytes == dp->i_d.di_size);
1188 ASSERT(dp->i_df.if_u1.if_data != NULL); 1191 ASSERT(ifp->if_u1.if_data != NULL);
1189 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count)); 1192 ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count));
1193 ASSERT(dp->i_d.di_nextents == 0);
1190 1194
1191 /* 1195 /*
1192 * Copy the directory into a temporary buffer. 1196 * Copy the directory into a temporary buffer.
1193 * Then pitch the incore inode data so we can make extents. 1197 * Then pitch the incore inode data so we can make extents.
1194 */ 1198 */
1195 sfp = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP); 1199 sfp = kmem_alloc(ifp->if_bytes, KM_SLEEP);
1196 memcpy(sfp, oldsfp, dp->i_df.if_bytes); 1200 memcpy(sfp, oldsfp, ifp->if_bytes);
1197 1201
1198 xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK); 1202 xfs_idata_realloc(dp, -ifp->if_bytes, XFS_DATA_FORK);
1203 xfs_bmap_local_to_extents_empty(dp, XFS_DATA_FORK);
1199 dp->i_d.di_size = 0; 1204 dp->i_d.di_size = 0;
1200 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
1201 1205
1202 /* 1206 /*
1203 * Add block 0 to the inode. 1207 * Add block 0 to the inode.