blob: 32d657fbe6a4fac9f9c38245bde7621c9b4740d3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +11003 * Copyright (c) 2013 Red Hat, Inc.
Nathan Scott7b718762005-11-02 14:58:39 +11004 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Nathan Scott7b718762005-11-02 14:58:39 +11006 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * published by the Free Software Foundation.
9 *
Nathan Scott7b718762005-11-02 14:58:39 +110010 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070014 *
Nathan Scott7b718762005-11-02 14:58:39 +110015 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110020#include "xfs_fs.h"
Dave Chinnera4fbe6a2013-10-23 10:51:50 +110021#include "xfs_format.h"
Dave Chinner239880e2013-10-23 10:50:10 +110022#include "xfs_log_format.h"
23#include "xfs_trans_resv.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include "xfs_sb.h"
David Chinnerda353b02007-08-28 14:00:13 +100025#include "xfs_ag.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include "xfs_mount.h"
Dave Chinner57062782013-10-15 09:17:51 +110027#include "xfs_da_format.h"
Nathan Scotta844f452005-11-02 14:38:42 +110028#include "xfs_da_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "xfs_inode.h"
Dave Chinner2b9ab5a2013-08-12 20:49:37 +100030#include "xfs_dir2.h"
Christoph Hellwig57926642011-07-13 13:43:48 +020031#include "xfs_dir2_priv.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_error.h"
Dave Chinner239880e2013-10-23 10:50:10 +110033#include "xfs_trans.h"
Dave Chinner33363fe2013-04-03 16:11:22 +110034#include "xfs_buf_item.h"
35#include "xfs_cksum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Linus Torvalds1da177e2005-04-16 15:20:36 -070037/*
38 * Check the consistency of the data block.
39 * The input can also be a block-format directory.
Dave Chinner82025d72012-11-12 22:54:12 +110040 * Return 0 is the buffer is good, otherwise an error.
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 */
Dave Chinner82025d72012-11-12 22:54:12 +110042int
Dave Chinner33363fe2013-04-03 16:11:22 +110043__xfs_dir3_data_check(
Dave Chinner1d9025e2012-06-22 18:50:14 +100044 struct xfs_inode *dp, /* incore inode pointer */
45 struct xfs_buf *bp) /* data block's buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -070046{
47 xfs_dir2_dataptr_t addr; /* addr for leaf lookup */
48 xfs_dir2_data_free_t *bf; /* bestfree table */
49 xfs_dir2_block_tail_t *btp=NULL; /* block tail */
50 int count; /* count of entries found */
Christoph Hellwigc2066e22011-07-08 14:35:38 +020051 xfs_dir2_data_hdr_t *hdr; /* data block header */
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 xfs_dir2_data_entry_t *dep; /* data entry */
53 xfs_dir2_data_free_t *dfp; /* bestfree entry */
54 xfs_dir2_data_unused_t *dup; /* unused entry */
55 char *endp; /* end of useful data */
56 int freeseen; /* mask of bestfrees seen */
57 xfs_dahash_t hash; /* hash of current name */
58 int i; /* leaf index */
59 int lastfree; /* last entry was unused */
60 xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */
61 xfs_mount_t *mp; /* filesystem mount point */
62 char *p; /* current data position */
63 int stale; /* count of stale leaves */
Barry Naujok5163f952008-05-21 16:41:01 +100064 struct xfs_name name;
Dave Chinner9d23fc82013-10-29 22:11:48 +110065 const struct xfs_dir_ops *ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Dave Chinner82025d72012-11-12 22:54:12 +110067 mp = bp->b_target->bt_mount;
Dave Chinner1d9025e2012-06-22 18:50:14 +100068 hdr = bp->b_addr;
Christoph Hellwigc2066e22011-07-08 14:35:38 +020069
Dave Chinner9d23fc82013-10-29 22:11:48 +110070 /*
Dave Chinner41419562013-10-29 22:11:50 +110071 * We can be passed a null dp here from a verifier, so we need to go the
72 * hard way to get them.
Dave Chinner9d23fc82013-10-29 22:11:48 +110073 */
Dave Chinner41419562013-10-29 22:11:50 +110074 ops = xfs_dir_get_ops(mp, dp);
Dave Chinner9d23fc82013-10-29 22:11:48 +110075
Dave Chinner82025d72012-11-12 22:54:12 +110076 switch (hdr->magic) {
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +110077 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
Dave Chinner82025d72012-11-12 22:54:12 +110078 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
Christoph Hellwigc2066e22011-07-08 14:35:38 +020079 btp = xfs_dir2_block_tail_p(mp, hdr);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +100080 lep = xfs_dir2_block_leaf_p(btp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 endp = (char *)lep;
Dave Chinner82025d72012-11-12 22:54:12 +110082 break;
Dave Chinner33363fe2013-04-03 16:11:22 +110083 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
Dave Chinner82025d72012-11-12 22:54:12 +110084 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
Christoph Hellwigc2066e22011-07-08 14:35:38 +020085 endp = (char *)hdr + mp->m_dirblksize;
Dave Chinner82025d72012-11-12 22:54:12 +110086 break;
87 default:
88 XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp);
89 return EFSCORRUPTED;
Christoph Hellwigc2066e22011-07-08 14:35:38 +020090 }
Dave Chinner2ca98772013-10-29 22:11:49 +110091 bf = ops->data_bestfree_p(hdr);
92 p = (char *)ops->data_entry_p(hdr);
Christoph Hellwigc2066e22011-07-08 14:35:38 +020093
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 count = lastfree = freeseen = 0;
95 /*
96 * Account for zero bestfree entries.
97 */
98 if (!bf[0].length) {
Dave Chinner82025d72012-11-12 22:54:12 +110099 XFS_WANT_CORRUPTED_RETURN(!bf[0].offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 freeseen |= 1 << 0;
101 }
102 if (!bf[1].length) {
Dave Chinner82025d72012-11-12 22:54:12 +1100103 XFS_WANT_CORRUPTED_RETURN(!bf[1].offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 freeseen |= 1 << 1;
105 }
106 if (!bf[2].length) {
Dave Chinner82025d72012-11-12 22:54:12 +1100107 XFS_WANT_CORRUPTED_RETURN(!bf[2].offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 freeseen |= 1 << 2;
109 }
Dave Chinner82025d72012-11-12 22:54:12 +1100110
111 XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[0].length) >=
112 be16_to_cpu(bf[1].length));
113 XFS_WANT_CORRUPTED_RETURN(be16_to_cpu(bf[1].length) >=
114 be16_to_cpu(bf[2].length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 /*
116 * Loop over the data/unused entries.
117 */
118 while (p < endp) {
119 dup = (xfs_dir2_data_unused_t *)p;
120 /*
121 * If it's unused, look for the space in the bestfree table.
122 * If we find it, account for that, else make sure it
123 * doesn't need to be there.
124 */
Nathan Scottad354eb2006-03-17 17:27:37 +1100125 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
Dave Chinner82025d72012-11-12 22:54:12 +1100126 XFS_WANT_CORRUPTED_RETURN(lastfree == 0);
127 XFS_WANT_CORRUPTED_RETURN(
128 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
129 (char *)dup - (char *)hdr);
Dave Chinner2ca98772013-10-29 22:11:49 +1100130 dfp = xfs_dir2_data_freefind(hdr, bf, dup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 if (dfp) {
132 i = (int)(dfp - bf);
Dave Chinner82025d72012-11-12 22:54:12 +1100133 XFS_WANT_CORRUPTED_RETURN(
134 (freeseen & (1 << i)) == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 freeseen |= 1 << i;
Nathan Scott70e73f52006-03-17 17:26:52 +1100136 } else {
Dave Chinner82025d72012-11-12 22:54:12 +1100137 XFS_WANT_CORRUPTED_RETURN(
138 be16_to_cpu(dup->length) <=
139 be16_to_cpu(bf[2].length));
Nathan Scott70e73f52006-03-17 17:26:52 +1100140 }
Nathan Scottad354eb2006-03-17 17:27:37 +1100141 p += be16_to_cpu(dup->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 lastfree = 1;
143 continue;
144 }
145 /*
146 * It's a real entry. Validate the fields.
147 * If this is a block directory then make sure it's
148 * in the leaf section of the block.
149 * The linear search is crude but this is DEBUG code.
150 */
151 dep = (xfs_dir2_data_entry_t *)p;
Dave Chinner82025d72012-11-12 22:54:12 +1100152 XFS_WANT_CORRUPTED_RETURN(dep->namelen != 0);
153 XFS_WANT_CORRUPTED_RETURN(
154 !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
155 XFS_WANT_CORRUPTED_RETURN(
Dave Chinner9d23fc82013-10-29 22:11:48 +1100156 be16_to_cpu(*ops->data_entry_tag_p(dep)) ==
Dave Chinner82025d72012-11-12 22:54:12 +1100157 (char *)dep - (char *)hdr);
Dave Chinner1c55cec2013-08-12 20:50:10 +1000158 XFS_WANT_CORRUPTED_RETURN(
Dave Chinner9d23fc82013-10-29 22:11:48 +1100159 ops->data_get_ftype(dep) < XFS_DIR3_FT_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 count++;
161 lastfree = 0;
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100162 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
163 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000164 addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 (xfs_dir2_data_aoff_t)
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200166 ((char *)dep - (char *)hdr));
Barry Naujok5163f952008-05-21 16:41:01 +1000167 name.name = dep->name;
168 name.len = dep->namelen;
169 hash = mp->m_dirnameops->hashname(&name);
Nathan Scotte922fff2006-03-17 17:27:56 +1100170 for (i = 0; i < be32_to_cpu(btp->count); i++) {
Nathan Scott3c1f9c12006-03-17 17:28:18 +1100171 if (be32_to_cpu(lep[i].address) == addr &&
172 be32_to_cpu(lep[i].hashval) == hash)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 break;
174 }
Dave Chinner82025d72012-11-12 22:54:12 +1100175 XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 }
Dave Chinner9d23fc82013-10-29 22:11:48 +1100177 p += ops->data_entsize(dep->namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 }
179 /*
180 * Need to have seen all the entries and all the bestfree slots.
181 */
Dave Chinner82025d72012-11-12 22:54:12 +1100182 XFS_WANT_CORRUPTED_RETURN(freeseen == 7);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100183 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
184 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
Nathan Scotte922fff2006-03-17 17:27:56 +1100185 for (i = stale = 0; i < be32_to_cpu(btp->count); i++) {
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200186 if (lep[i].address ==
187 cpu_to_be32(XFS_DIR2_NULL_DATAPTR))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 stale++;
189 if (i > 0)
Dave Chinner82025d72012-11-12 22:54:12 +1100190 XFS_WANT_CORRUPTED_RETURN(
191 be32_to_cpu(lep[i].hashval) >=
192 be32_to_cpu(lep[i - 1].hashval));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 }
Dave Chinner82025d72012-11-12 22:54:12 +1100194 XFS_WANT_CORRUPTED_RETURN(count ==
195 be32_to_cpu(btp->count) - be32_to_cpu(btp->stale));
196 XFS_WANT_CORRUPTED_RETURN(stale == be32_to_cpu(btp->stale));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 }
Dave Chinner82025d72012-11-12 22:54:12 +1100198 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Dave Chinner33363fe2013-04-03 16:11:22 +1100201static bool
202xfs_dir3_data_verify(
Dave Chinnere4813572012-11-12 22:54:14 +1100203 struct xfs_buf *bp)
204{
205 struct xfs_mount *mp = bp->b_target->bt_mount;
Dave Chinner33363fe2013-04-03 16:11:22 +1100206 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
Dave Chinnere4813572012-11-12 22:54:14 +1100207
Dave Chinner33363fe2013-04-03 16:11:22 +1100208 if (xfs_sb_version_hascrc(&mp->m_sb)) {
209 if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC))
210 return false;
211 if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_uuid))
212 return false;
213 if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
214 return false;
215 } else {
216 if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC))
217 return false;
Dave Chinnere4813572012-11-12 22:54:14 +1100218 }
Dave Chinner33363fe2013-04-03 16:11:22 +1100219 if (__xfs_dir3_data_check(NULL, bp))
220 return false;
221 return true;
Dave Chinner612cfbf2012-11-14 17:52:32 +1100222}
Dave Chinnere4813572012-11-12 22:54:14 +1100223
Dave Chinner1813dd62012-11-14 17:54:40 +1100224/*
225 * Readahead of the first block of the directory when it is opened is completely
226 * oblivious to the format of the directory. Hence we can either get a block
227 * format buffer or a data format buffer on readahead.
228 */
229static void
Dave Chinner33363fe2013-04-03 16:11:22 +1100230xfs_dir3_data_reada_verify(
Dave Chinner1813dd62012-11-14 17:54:40 +1100231 struct xfs_buf *bp)
Dave Chinner612cfbf2012-11-14 17:52:32 +1100232{
Dave Chinner1813dd62012-11-14 17:54:40 +1100233 struct xfs_mount *mp = bp->b_target->bt_mount;
234 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
235
236 switch (hdr->magic) {
237 case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC):
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100238 case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC):
239 bp->b_ops = &xfs_dir3_block_buf_ops;
Dave Chinner1813dd62012-11-14 17:54:40 +1100240 bp->b_ops->verify_read(bp);
241 return;
242 case cpu_to_be32(XFS_DIR2_DATA_MAGIC):
Dave Chinner33363fe2013-04-03 16:11:22 +1100243 case cpu_to_be32(XFS_DIR3_DATA_MAGIC):
244 xfs_dir3_data_verify(bp);
Dave Chinner1813dd62012-11-14 17:54:40 +1100245 return;
246 default:
247 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, hdr);
248 xfs_buf_ioerror(bp, EFSCORRUPTED);
249 break;
250 }
Dave Chinner612cfbf2012-11-14 17:52:32 +1100251}
252
Dave Chinnerb0f539d2012-11-14 17:53:49 +1100253static void
Dave Chinner33363fe2013-04-03 16:11:22 +1100254xfs_dir3_data_read_verify(
Dave Chinner612cfbf2012-11-14 17:52:32 +1100255 struct xfs_buf *bp)
256{
Dave Chinner33363fe2013-04-03 16:11:22 +1100257 struct xfs_mount *mp = bp->b_target->bt_mount;
258
259 if ((xfs_sb_version_hascrc(&mp->m_sb) &&
260 !xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
261 XFS_DIR3_DATA_CRC_OFF)) ||
262 !xfs_dir3_data_verify(bp)) {
263 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
264 xfs_buf_ioerror(bp, EFSCORRUPTED);
265 }
Dave Chinnere4813572012-11-12 22:54:14 +1100266}
267
Dave Chinner1813dd62012-11-14 17:54:40 +1100268static void
Dave Chinner33363fe2013-04-03 16:11:22 +1100269xfs_dir3_data_write_verify(
Dave Chinner1813dd62012-11-14 17:54:40 +1100270 struct xfs_buf *bp)
271{
Dave Chinner33363fe2013-04-03 16:11:22 +1100272 struct xfs_mount *mp = bp->b_target->bt_mount;
273 struct xfs_buf_log_item *bip = bp->b_fspriv;
274 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
275
276 if (!xfs_dir3_data_verify(bp)) {
277 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
278 xfs_buf_ioerror(bp, EFSCORRUPTED);
279 return;
280 }
281
282 if (!xfs_sb_version_hascrc(&mp->m_sb))
283 return;
284
285 if (bip)
286 hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn);
287
288 xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_DIR3_DATA_CRC_OFF);
Dave Chinner1813dd62012-11-14 17:54:40 +1100289}
290
Dave Chinner33363fe2013-04-03 16:11:22 +1100291const struct xfs_buf_ops xfs_dir3_data_buf_ops = {
292 .verify_read = xfs_dir3_data_read_verify,
293 .verify_write = xfs_dir3_data_write_verify,
Dave Chinner1813dd62012-11-14 17:54:40 +1100294};
295
Dave Chinner33363fe2013-04-03 16:11:22 +1100296static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = {
297 .verify_read = xfs_dir3_data_reada_verify,
298 .verify_write = xfs_dir3_data_write_verify,
Dave Chinner1813dd62012-11-14 17:54:40 +1100299};
300
Dave Chinner612cfbf2012-11-14 17:52:32 +1100301
Dave Chinnere4813572012-11-12 22:54:14 +1100302int
Dave Chinner33363fe2013-04-03 16:11:22 +1100303xfs_dir3_data_read(
Dave Chinnere4813572012-11-12 22:54:14 +1100304 struct xfs_trans *tp,
305 struct xfs_inode *dp,
306 xfs_dablk_t bno,
307 xfs_daddr_t mapped_bno,
308 struct xfs_buf **bpp)
309{
Dave Chinnerd75afeb2013-04-03 16:11:29 +1100310 int err;
311
312 err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp,
Dave Chinner33363fe2013-04-03 16:11:22 +1100313 XFS_DATA_FORK, &xfs_dir3_data_buf_ops);
Dave Chinnerd75afeb2013-04-03 16:11:29 +1100314 if (!err && tp)
Dave Chinner61fe1352013-04-03 16:11:30 +1100315 xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF);
Dave Chinnerd75afeb2013-04-03 16:11:29 +1100316 return err;
Dave Chinnere4813572012-11-12 22:54:14 +1100317}
318
Dave Chinnerda6958c2012-11-12 22:54:18 +1100319int
Dave Chinner33363fe2013-04-03 16:11:22 +1100320xfs_dir3_data_readahead(
Dave Chinnerda6958c2012-11-12 22:54:18 +1100321 struct xfs_trans *tp,
322 struct xfs_inode *dp,
323 xfs_dablk_t bno,
324 xfs_daddr_t mapped_bno)
325{
326 return xfs_da_reada_buf(tp, dp, bno, mapped_bno,
Dave Chinner33363fe2013-04-03 16:11:22 +1100327 XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops);
Dave Chinnerda6958c2012-11-12 22:54:18 +1100328}
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330/*
331 * Given a data block and an unused entry from that block,
332 * return the bestfree entry if any that corresponds to it.
333 */
Dave Chinner2b9ab5a2013-08-12 20:49:37 +1000334xfs_dir2_data_free_t *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335xfs_dir2_data_freefind(
Dave Chinner2ca98772013-10-29 22:11:49 +1100336 struct xfs_dir2_data_hdr *hdr, /* data block header */
337 struct xfs_dir2_data_free *bf, /* bestfree table pointer */
338 struct xfs_dir2_data_unused *dup) /* unused space */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339{
340 xfs_dir2_data_free_t *dfp; /* bestfree entry */
341 xfs_dir2_data_aoff_t off; /* offset value needed */
Dave Chinnerb49a0c12013-08-12 20:49:51 +1000342#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 int matched; /* matched the value */
344 int seenzero; /* saw a 0 bestfree entry */
345#endif
346
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200347 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100348
Dave Chinnerb49a0c12013-08-12 20:49:51 +1000349#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 /*
351 * Validate some consistency in the bestfree table.
352 * Check order, non-overlapping entries, and if we find the
353 * one we're looking for it has to be exact.
354 */
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200355 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinner33363fe2013-04-03 16:11:22 +1100356 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100357 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
358 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
359 for (dfp = &bf[0], seenzero = matched = 0;
360 dfp < &bf[XFS_DIR2_DATA_FD_COUNT];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 dfp++) {
362 if (!dfp->offset) {
363 ASSERT(!dfp->length);
364 seenzero = 1;
365 continue;
366 }
367 ASSERT(seenzero == 0);
Nathan Scott70e73f52006-03-17 17:26:52 +1100368 if (be16_to_cpu(dfp->offset) == off) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 matched = 1;
Nathan Scottad354eb2006-03-17 17:27:37 +1100370 ASSERT(dfp->length == dup->length);
Nathan Scott70e73f52006-03-17 17:26:52 +1100371 } else if (off < be16_to_cpu(dfp->offset))
Nathan Scottad354eb2006-03-17 17:27:37 +1100372 ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 else
Nathan Scott70e73f52006-03-17 17:26:52 +1100374 ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off);
Nathan Scottad354eb2006-03-17 17:27:37 +1100375 ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length));
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100376 if (dfp > &bf[0])
Nathan Scott70e73f52006-03-17 17:26:52 +1100377 ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 }
379#endif
380 /*
381 * If this is smaller than the smallest bestfree entry,
382 * it can't be there since they're sorted.
383 */
Nathan Scottad354eb2006-03-17 17:27:37 +1100384 if (be16_to_cpu(dup->length) <
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100385 be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 return NULL;
387 /*
388 * Look at the three bestfree entries for our guy.
389 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100390 for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 if (!dfp->offset)
392 return NULL;
Nathan Scott70e73f52006-03-17 17:26:52 +1100393 if (be16_to_cpu(dfp->offset) == off)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 return dfp;
395 }
396 /*
397 * Didn't find it. This only happens if there are duplicate lengths.
398 */
399 return NULL;
400}
401
402/*
403 * Insert an unused-space entry into the bestfree table.
404 */
405xfs_dir2_data_free_t * /* entry inserted */
406xfs_dir2_data_freeinsert(
Dave Chinner2ca98772013-10-29 22:11:49 +1100407 struct xfs_dir2_data_hdr *hdr, /* data block pointer */
408 struct xfs_dir2_data_free *dfp, /* bestfree table pointer */
409 struct xfs_dir2_data_unused *dup, /* unused space */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 int *loghead) /* log the data header (out) */
411{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412 xfs_dir2_data_free_t new; /* new bestfree entry */
413
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200414 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100415 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
416 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
417 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
418
Nathan Scott70e73f52006-03-17 17:26:52 +1100419 new.length = dup->length;
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200420 new.offset = cpu_to_be16((char *)dup - (char *)hdr);
421
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 /*
423 * Insert at position 0, 1, or 2; or not at all.
424 */
Nathan Scott70e73f52006-03-17 17:26:52 +1100425 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 dfp[2] = dfp[1];
427 dfp[1] = dfp[0];
428 dfp[0] = new;
429 *loghead = 1;
430 return &dfp[0];
431 }
Nathan Scott70e73f52006-03-17 17:26:52 +1100432 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 dfp[2] = dfp[1];
434 dfp[1] = new;
435 *loghead = 1;
436 return &dfp[1];
437 }
Nathan Scott70e73f52006-03-17 17:26:52 +1100438 if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 dfp[2] = new;
440 *loghead = 1;
441 return &dfp[2];
442 }
443 return NULL;
444}
445
446/*
447 * Remove a bestfree entry from the table.
448 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +1000449STATIC void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450xfs_dir2_data_freeremove(
Dave Chinner2ca98772013-10-29 22:11:49 +1100451 struct xfs_dir2_data_hdr *hdr, /* data block header */
452 struct xfs_dir2_data_free *bf, /* bestfree table pointer */
453 struct xfs_dir2_data_free *dfp, /* bestfree entry pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 int *loghead) /* out: log data header */
455{
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100456
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200457 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100458 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
459 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
460 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 /*
463 * It's the first entry, slide the next 2 up.
464 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100465 if (dfp == &bf[0]) {
466 bf[0] = bf[1];
467 bf[1] = bf[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469 /*
470 * It's the second entry, slide the 3rd entry up.
471 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100472 else if (dfp == &bf[1])
473 bf[1] = bf[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 /*
475 * Must be the last entry.
476 */
477 else
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100478 ASSERT(dfp == &bf[2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 /*
480 * Clear the 3rd entry, must be zero now.
481 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100482 bf[2].length = 0;
483 bf[2].offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 *loghead = 1;
485}
486
487/*
488 * Given a data block, reconstruct its bestfree map.
489 */
490void
491xfs_dir2_data_freescan(
Dave Chinner9d23fc82013-10-29 22:11:48 +1100492 struct xfs_inode *dp,
493 struct xfs_dir2_data_hdr *hdr,
494 int *loghead)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
496 xfs_dir2_block_tail_t *btp; /* block tail */
497 xfs_dir2_data_entry_t *dep; /* active data entry */
498 xfs_dir2_data_unused_t *dup; /* unused data entry */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100499 struct xfs_dir2_data_free *bf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 char *endp; /* end of block's data */
501 char *p; /* current entry pointer */
502
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200503 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinner33363fe2013-04-03 16:11:22 +1100504 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100505 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
506 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 /*
509 * Start by clearing the table.
510 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100511 bf = dp->d_ops->data_bestfree_p(hdr);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100512 memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 *loghead = 1;
514 /*
515 * Set up pointers.
516 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100517 p = (char *)dp->d_ops->data_entry_p(hdr);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100518 if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
519 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) {
Dave Chinner9d23fc82013-10-29 22:11:48 +1100520 btp = xfs_dir2_block_tail_p(dp->i_mount, hdr);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000521 endp = (char *)xfs_dir2_block_leaf_p(btp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 } else
Dave Chinner9d23fc82013-10-29 22:11:48 +1100523 endp = (char *)hdr + dp->i_mount->m_dirblksize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 /*
525 * Loop over the block's entries.
526 */
527 while (p < endp) {
528 dup = (xfs_dir2_data_unused_t *)p;
529 /*
530 * If it's a free entry, insert it.
531 */
Nathan Scottad354eb2006-03-17 17:27:37 +1100532 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200533 ASSERT((char *)dup - (char *)hdr ==
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000534 be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
Dave Chinner2ca98772013-10-29 22:11:49 +1100535 xfs_dir2_data_freeinsert(hdr, bf, dup, loghead);
Nathan Scottad354eb2006-03-17 17:27:37 +1100536 p += be16_to_cpu(dup->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 }
538 /*
539 * For active entries, check their tags and skip them.
540 */
541 else {
542 dep = (xfs_dir2_data_entry_t *)p;
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200543 ASSERT((char *)dep - (char *)hdr ==
Dave Chinner9d23fc82013-10-29 22:11:48 +1100544 be16_to_cpu(*dp->d_ops->data_entry_tag_p(dep)));
545 p += dp->d_ops->data_entsize(dep->namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 }
547 }
548}
549
550/*
551 * Initialize a data block at the given block number in the directory.
552 * Give back the buffer for the created block.
553 */
554int /* error */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100555xfs_dir3_data_init(
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 xfs_da_args_t *args, /* directory operation args */
557 xfs_dir2_db_t blkno, /* logical dir block number */
Dave Chinner1d9025e2012-06-22 18:50:14 +1000558 struct xfs_buf **bpp) /* output block buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
Dave Chinner1d9025e2012-06-22 18:50:14 +1000560 struct xfs_buf *bp; /* block buffer */
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200561 xfs_dir2_data_hdr_t *hdr; /* data block header */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 xfs_inode_t *dp; /* incore directory inode */
563 xfs_dir2_data_unused_t *dup; /* unused entry pointer */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100564 struct xfs_dir2_data_free *bf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 int error; /* error return value */
566 int i; /* bestfree index */
567 xfs_mount_t *mp; /* filesystem mount point */
568 xfs_trans_t *tp; /* transaction pointer */
569 int t; /* temp */
570
571 dp = args->dp;
572 mp = dp->i_mount;
573 tp = args->trans;
574 /*
575 * Get the buffer set up for the block.
576 */
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000577 error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 XFS_DATA_FORK);
Dave Chinnerb0f539d2012-11-14 17:53:49 +1100579 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 return error;
Dave Chinner33363fe2013-04-03 16:11:22 +1100581 bp->b_ops = &xfs_dir3_data_buf_ops;
Dave Chinner61fe1352013-04-03 16:11:30 +1100582 xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF);
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 /*
585 * Initialize the header.
586 */
Dave Chinner1d9025e2012-06-22 18:50:14 +1000587 hdr = bp->b_addr;
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100588 if (xfs_sb_version_hascrc(&mp->m_sb)) {
589 struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr;
590
591 memset(hdr3, 0, sizeof(*hdr3));
592 hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC);
593 hdr3->blkno = cpu_to_be64(bp->b_bn);
594 hdr3->owner = cpu_to_be64(dp->i_ino);
595 uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
596
597 } else
598 hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
599
Dave Chinner2ca98772013-10-29 22:11:49 +1100600 bf = dp->d_ops->data_bestfree_p(hdr);
601 bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) {
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100603 bf[i].length = 0;
604 bf[i].offset = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 /*
608 * Set up an unused entry for the block's body.
609 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100610 dup = dp->d_ops->data_unused_p(hdr);
Nathan Scottad354eb2006-03-17 17:27:37 +1100611 dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
Dave Chinner2ca98772013-10-29 22:11:49 +1100613 t = mp->m_dirblksize - (uint)dp->d_ops->data_entry_offset();
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100614 bf[0].length = cpu_to_be16(t);
Nathan Scottad354eb2006-03-17 17:27:37 +1100615 dup->length = cpu_to_be16(t);
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200616 *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 /*
618 * Log it and return it.
619 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100620 xfs_dir2_data_log_header(tp, dp, bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 xfs_dir2_data_log_unused(tp, bp, dup);
622 *bpp = bp;
623 return 0;
624}
625
626/*
627 * Log an active data entry from the block.
628 */
629void
630xfs_dir2_data_log_entry(
Dave Chinner1d9025e2012-06-22 18:50:14 +1000631 struct xfs_trans *tp,
Dave Chinner9d23fc82013-10-29 22:11:48 +1100632 struct xfs_inode *dp,
Dave Chinner1d9025e2012-06-22 18:50:14 +1000633 struct xfs_buf *bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 xfs_dir2_data_entry_t *dep) /* data entry pointer */
635{
Dave Chinner0cb97762013-08-12 20:50:09 +1000636 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200638 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinner33363fe2013-04-03 16:11:22 +1100639 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100640 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
641 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200642
Dave Chinner1d9025e2012-06-22 18:50:14 +1000643 xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
Dave Chinner9d23fc82013-10-29 22:11:48 +1100644 (uint)((char *)(dp->d_ops->data_entry_tag_p(dep) + 1) -
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200645 (char *)hdr - 1));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646}
647
648/*
649 * Log a data block header.
650 */
651void
652xfs_dir2_data_log_header(
Dave Chinner1d9025e2012-06-22 18:50:14 +1000653 struct xfs_trans *tp,
Dave Chinner2ca98772013-10-29 22:11:49 +1100654 struct xfs_inode *dp,
Dave Chinner1d9025e2012-06-22 18:50:14 +1000655 struct xfs_buf *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
Dave Chinner2ca98772013-10-29 22:11:49 +1100657#ifdef DEBUG
658 struct xfs_dir2_data_hdr *hdr = bp->b_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200660 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinner33363fe2013-04-03 16:11:22 +1100661 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100662 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
663 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
Dave Chinner2ca98772013-10-29 22:11:49 +1100664#endif
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200665
Dave Chinner2ca98772013-10-29 22:11:49 +1100666 xfs_trans_log_buf(tp, bp, 0, dp->d_ops->data_entry_offset() - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667}
668
669/*
670 * Log a data unused entry.
671 */
672void
673xfs_dir2_data_log_unused(
Dave Chinner1d9025e2012-06-22 18:50:14 +1000674 struct xfs_trans *tp,
675 struct xfs_buf *bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 xfs_dir2_data_unused_t *dup) /* data unused pointer */
677{
Dave Chinner1d9025e2012-06-22 18:50:14 +1000678 xfs_dir2_data_hdr_t *hdr = bp->b_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200680 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinner33363fe2013-04-03 16:11:22 +1100681 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100682 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
683 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200684
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 /*
686 * Log the first part of the unused entry.
687 */
Dave Chinner1d9025e2012-06-22 18:50:14 +1000688 xfs_trans_log_buf(tp, bp, (uint)((char *)dup - (char *)hdr),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 (uint)((char *)&dup->length + sizeof(dup->length) -
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200690 1 - (char *)hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 /*
692 * Log the end (tag) of the unused entry.
693 */
Dave Chinner1d9025e2012-06-22 18:50:14 +1000694 xfs_trans_log_buf(tp, bp,
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200695 (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr),
696 (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 sizeof(xfs_dir2_data_off_t) - 1));
698}
699
700/*
701 * Make a byte range in the data block unused.
702 * Its current contents are unimportant.
703 */
704void
705xfs_dir2_data_make_free(
Dave Chinner1d9025e2012-06-22 18:50:14 +1000706 struct xfs_trans *tp,
Dave Chinner2ca98772013-10-29 22:11:49 +1100707 struct xfs_inode *dp,
Dave Chinner1d9025e2012-06-22 18:50:14 +1000708 struct xfs_buf *bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 xfs_dir2_data_aoff_t offset, /* starting byte offset */
710 xfs_dir2_data_aoff_t len, /* length in bytes */
711 int *needlogp, /* out: log header */
712 int *needscanp) /* out: regen bestfree */
713{
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200714 xfs_dir2_data_hdr_t *hdr; /* data block pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 xfs_dir2_data_free_t *dfp; /* bestfree pointer */
716 char *endptr; /* end of data area */
717 xfs_mount_t *mp; /* filesystem mount point */
718 int needscan; /* need to regen bestfree */
719 xfs_dir2_data_unused_t *newdup; /* new unused entry */
720 xfs_dir2_data_unused_t *postdup; /* unused entry after us */
721 xfs_dir2_data_unused_t *prevdup; /* unused entry before us */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100722 struct xfs_dir2_data_free *bf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723
724 mp = tp->t_mountp;
Dave Chinner1d9025e2012-06-22 18:50:14 +1000725 hdr = bp->b_addr;
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200726
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 /*
728 * Figure out where the end of the data area is.
729 */
Dave Chinner33363fe2013-04-03 16:11:22 +1100730 if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
731 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC))
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200732 endptr = (char *)hdr + mp->m_dirblksize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 else {
734 xfs_dir2_block_tail_t *btp; /* block tail */
735
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100736 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
737 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200738 btp = xfs_dir2_block_tail_p(mp, hdr);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000739 endptr = (char *)xfs_dir2_block_leaf_p(btp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 }
741 /*
742 * If this isn't the start of the block, then back up to
743 * the previous entry and see if it's free.
744 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100745 if (offset > dp->d_ops->data_entry_offset()) {
Nathan Scott3d693c62006-03-17 17:28:27 +1100746 __be16 *tagp; /* tag just before us */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200748 tagp = (__be16 *)((char *)hdr + offset) - 1;
749 prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp));
Nathan Scottad354eb2006-03-17 17:27:37 +1100750 if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 prevdup = NULL;
752 } else
753 prevdup = NULL;
754 /*
755 * If this isn't the end of the block, see if the entry after
756 * us is free.
757 */
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200758 if ((char *)hdr + offset + len < endptr) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 postdup =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200760 (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
Nathan Scottad354eb2006-03-17 17:27:37 +1100761 if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 postdup = NULL;
763 } else
764 postdup = NULL;
765 ASSERT(*needscanp == 0);
766 needscan = 0;
767 /*
768 * Previous and following entries are both free,
769 * merge everything into a single free entry.
770 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100771 bf = dp->d_ops->data_bestfree_p(hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (prevdup && postdup) {
773 xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */
774
775 /*
776 * See if prevdup and/or postdup are in bestfree table.
777 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100778 dfp = xfs_dir2_data_freefind(hdr, bf, prevdup);
779 dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 /*
781 * We need a rescan unless there are exactly 2 free entries
782 * namely our two. Then we know what's happening, otherwise
783 * since the third bestfree is there, there might be more
784 * entries.
785 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100786 needscan = (bf[2].length != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 /*
788 * Fix up the new big freespace.
789 */
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800790 be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length));
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000791 *xfs_dir2_data_unused_tag_p(prevdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200792 cpu_to_be16((char *)prevdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 xfs_dir2_data_log_unused(tp, bp, prevdup);
794 if (!needscan) {
795 /*
796 * Has to be the case that entries 0 and 1 are
797 * dfp and dfp2 (don't know which is which), and
798 * entry 2 is empty.
799 * Remove entry 1 first then entry 0.
800 */
801 ASSERT(dfp && dfp2);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100802 if (dfp == &bf[1]) {
803 dfp = &bf[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 ASSERT(dfp2 == dfp);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100805 dfp2 = &bf[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 }
Dave Chinner2ca98772013-10-29 22:11:49 +1100807 xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp);
808 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 /*
810 * Now insert the new entry.
811 */
Dave Chinner2ca98772013-10-29 22:11:49 +1100812 dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup,
813 needlogp);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100814 ASSERT(dfp == &bf[0]);
Nathan Scottad354eb2006-03-17 17:27:37 +1100815 ASSERT(dfp->length == prevdup->length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 ASSERT(!dfp[1].length);
817 ASSERT(!dfp[2].length);
818 }
819 }
820 /*
821 * The entry before us is free, merge with it.
822 */
823 else if (prevdup) {
Dave Chinner2ca98772013-10-29 22:11:49 +1100824 dfp = xfs_dir2_data_freefind(hdr, bf, prevdup);
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800825 be16_add_cpu(&prevdup->length, len);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000826 *xfs_dir2_data_unused_tag_p(prevdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200827 cpu_to_be16((char *)prevdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 xfs_dir2_data_log_unused(tp, bp, prevdup);
829 /*
830 * If the previous entry was in the table, the new entry
831 * is longer, so it will be in the table too. Remove
832 * the old one and add the new one.
833 */
834 if (dfp) {
Dave Chinner2ca98772013-10-29 22:11:49 +1100835 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
836 xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 }
838 /*
839 * Otherwise we need a scan if the new entry is big enough.
840 */
Nathan Scott70e73f52006-03-17 17:26:52 +1100841 else {
Nathan Scottad354eb2006-03-17 17:27:37 +1100842 needscan = be16_to_cpu(prevdup->length) >
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100843 be16_to_cpu(bf[2].length);
Nathan Scott70e73f52006-03-17 17:26:52 +1100844 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846 /*
847 * The following entry is free, merge with it.
848 */
849 else if (postdup) {
Dave Chinner2ca98772013-10-29 22:11:49 +1100850 dfp = xfs_dir2_data_freefind(hdr, bf, postdup);
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200851 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
Nathan Scottad354eb2006-03-17 17:27:37 +1100852 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
853 newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000854 *xfs_dir2_data_unused_tag_p(newdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200855 cpu_to_be16((char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 xfs_dir2_data_log_unused(tp, bp, newdup);
857 /*
858 * If the following entry was in the table, the new entry
859 * is longer, so it will be in the table too. Remove
860 * the old one and add the new one.
861 */
862 if (dfp) {
Dave Chinner2ca98772013-10-29 22:11:49 +1100863 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
864 xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 }
866 /*
867 * Otherwise we need a scan if the new entry is big enough.
868 */
Nathan Scott70e73f52006-03-17 17:26:52 +1100869 else {
Nathan Scottad354eb2006-03-17 17:27:37 +1100870 needscan = be16_to_cpu(newdup->length) >
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100871 be16_to_cpu(bf[2].length);
Nathan Scott70e73f52006-03-17 17:26:52 +1100872 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 }
874 /*
875 * Neither neighbor is free. Make a new entry.
876 */
877 else {
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200878 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset);
Nathan Scottad354eb2006-03-17 17:27:37 +1100879 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
880 newdup->length = cpu_to_be16(len);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000881 *xfs_dir2_data_unused_tag_p(newdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200882 cpu_to_be16((char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 xfs_dir2_data_log_unused(tp, bp, newdup);
Dave Chinner2ca98772013-10-29 22:11:49 +1100884 xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 }
886 *needscanp = needscan;
887}
888
889/*
890 * Take a byte range out of an existing unused space and make it un-free.
891 */
892void
893xfs_dir2_data_use_free(
Dave Chinner1d9025e2012-06-22 18:50:14 +1000894 struct xfs_trans *tp,
Dave Chinner2ca98772013-10-29 22:11:49 +1100895 struct xfs_inode *dp,
Dave Chinner1d9025e2012-06-22 18:50:14 +1000896 struct xfs_buf *bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 xfs_dir2_data_unused_t *dup, /* unused entry */
898 xfs_dir2_data_aoff_t offset, /* starting offset to use */
899 xfs_dir2_data_aoff_t len, /* length to use */
900 int *needlogp, /* out: need to log header */
901 int *needscanp) /* out: need regen bestfree */
902{
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200903 xfs_dir2_data_hdr_t *hdr; /* data block header */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 xfs_dir2_data_free_t *dfp; /* bestfree pointer */
905 int matchback; /* matches end of freespace */
906 int matchfront; /* matches start of freespace */
907 int needscan; /* need to regen bestfree */
908 xfs_dir2_data_unused_t *newdup; /* new unused entry */
909 xfs_dir2_data_unused_t *newdup2; /* another new unused entry */
910 int oldlen; /* old unused entry's length */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100911 struct xfs_dir2_data_free *bf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912
Dave Chinner1d9025e2012-06-22 18:50:14 +1000913 hdr = bp->b_addr;
Christoph Hellwig69ef9212011-07-08 14:36:05 +0200914 ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
Dave Chinner33363fe2013-04-03 16:11:22 +1100915 hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100916 hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
917 hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
Nathan Scottad354eb2006-03-17 17:27:37 +1100918 ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200919 ASSERT(offset >= (char *)dup - (char *)hdr);
920 ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr);
921 ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 /*
923 * Look up the entry in the bestfree table.
924 */
Nathan Scottad354eb2006-03-17 17:27:37 +1100925 oldlen = be16_to_cpu(dup->length);
Dave Chinner2ca98772013-10-29 22:11:49 +1100926 bf = dp->d_ops->data_bestfree_p(hdr);
927 dfp = xfs_dir2_data_freefind(hdr, bf, dup);
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100928 ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 /*
930 * Check for alignment with front and back of the entry.
931 */
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200932 matchfront = (char *)dup - (char *)hdr == offset;
933 matchback = (char *)dup + oldlen - (char *)hdr == offset + len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 ASSERT(*needscanp == 0);
935 needscan = 0;
936 /*
937 * If we matched it exactly we just need to get rid of it from
938 * the bestfree table.
939 */
940 if (matchfront && matchback) {
941 if (dfp) {
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100942 needscan = (bf[2].offset != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 if (!needscan)
Dave Chinner2ca98772013-10-29 22:11:49 +1100944 xfs_dir2_data_freeremove(hdr, bf, dfp,
945 needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946 }
947 }
948 /*
949 * We match the first part of the entry.
950 * Make a new entry with the remaining freespace.
951 */
952 else if (matchfront) {
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200953 newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
Nathan Scottad354eb2006-03-17 17:27:37 +1100954 newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
955 newdup->length = cpu_to_be16(oldlen - len);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000956 *xfs_dir2_data_unused_tag_p(newdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200957 cpu_to_be16((char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 xfs_dir2_data_log_unused(tp, bp, newdup);
959 /*
960 * If it was in the table, remove it and add the new one.
961 */
962 if (dfp) {
Dave Chinner2ca98772013-10-29 22:11:49 +1100963 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
964 dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
965 needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 ASSERT(dfp != NULL);
Nathan Scottad354eb2006-03-17 17:27:37 +1100967 ASSERT(dfp->length == newdup->length);
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200968 ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 /*
970 * If we got inserted at the last slot,
971 * that means we don't know if there was a better
972 * choice for the last slot, or not. Rescan.
973 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +1100974 needscan = dfp == &bf[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 }
976 }
977 /*
978 * We match the last part of the entry.
979 * Trim the allocated space off the tail of the entry.
980 */
981 else if (matchback) {
982 newdup = dup;
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200983 newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +1000984 *xfs_dir2_data_unused_tag_p(newdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200985 cpu_to_be16((char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 xfs_dir2_data_log_unused(tp, bp, newdup);
987 /*
988 * If it was in the table, remove it and add the new one.
989 */
990 if (dfp) {
Dave Chinner2ca98772013-10-29 22:11:49 +1100991 xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp);
992 dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup,
993 needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 ASSERT(dfp != NULL);
Nathan Scottad354eb2006-03-17 17:27:37 +1100995 ASSERT(dfp->length == newdup->length);
Christoph Hellwigc2066e22011-07-08 14:35:38 +0200996 ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 /*
998 * If we got inserted at the last slot,
999 * that means we don't know if there was a better
1000 * choice for the last slot, or not. Rescan.
1001 */
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +11001002 needscan = dfp == &bf[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
1004 }
1005 /*
1006 * Poking out the middle of an entry.
1007 * Make two new entries.
1008 */
1009 else {
1010 newdup = dup;
Christoph Hellwigc2066e22011-07-08 14:35:38 +02001011 newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup);
Christoph Hellwigbbaaf532007-06-28 16:43:50 +10001012 *xfs_dir2_data_unused_tag_p(newdup) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +02001013 cpu_to_be16((char *)newdup - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 xfs_dir2_data_log_unused(tp, bp, newdup);
Christoph Hellwigc2066e22011-07-08 14:35:38 +02001015 newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len);
Nathan Scottad354eb2006-03-17 17:27:37 +11001016 newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
1017 newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
Christoph Hellwigbbaaf532007-06-28 16:43:50 +10001018 *xfs_dir2_data_unused_tag_p(newdup2) =
Christoph Hellwigc2066e22011-07-08 14:35:38 +02001019 cpu_to_be16((char *)newdup2 - (char *)hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 xfs_dir2_data_log_unused(tp, bp, newdup2);
1021 /*
1022 * If the old entry was in the table, we need to scan
1023 * if the 3rd entry was valid, since these entries
1024 * are smaller than the old one.
1025 * If we don't need to scan that means there were 1 or 2
1026 * entries in the table, and removing the old and adding
1027 * the 2 new will work.
1028 */
1029 if (dfp) {
Dave Chinnerf5f3d9b2013-04-03 16:11:20 +11001030 needscan = (bf[2].length != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (!needscan) {
Dave Chinner2ca98772013-10-29 22:11:49 +11001032 xfs_dir2_data_freeremove(hdr, bf, dfp,
1033 needlogp);
1034 xfs_dir2_data_freeinsert(hdr, bf, newdup,
1035 needlogp);
1036 xfs_dir2_data_freeinsert(hdr, bf, newdup2,
Christoph Hellwigc2066e22011-07-08 14:35:38 +02001037 needlogp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 }
1039 }
1040 }
1041 *needscanp = needscan;
1042}