[XFS] Add op_flags field and helpers to xfs_da_args
[safe/jmp/linux-2.6] / fs / xfs / xfs_dir2.c
1 /*
2  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18 #include "xfs.h"
19 #include "xfs_fs.h"
20 #include "xfs_types.h"
21 #include "xfs_bit.h"
22 #include "xfs_log.h"
23 #include "xfs_inum.h"
24 #include "xfs_trans.h"
25 #include "xfs_sb.h"
26 #include "xfs_ag.h"
27 #include "xfs_dir2.h"
28 #include "xfs_dmapi.h"
29 #include "xfs_mount.h"
30 #include "xfs_da_btree.h"
31 #include "xfs_bmap_btree.h"
32 #include "xfs_alloc_btree.h"
33 #include "xfs_dir2_sf.h"
34 #include "xfs_attr_sf.h"
35 #include "xfs_dinode.h"
36 #include "xfs_inode.h"
37 #include "xfs_inode_item.h"
38 #include "xfs_bmap.h"
39 #include "xfs_dir2_data.h"
40 #include "xfs_dir2_leaf.h"
41 #include "xfs_dir2_block.h"
42 #include "xfs_dir2_node.h"
43 #include "xfs_dir2_trace.h"
44 #include "xfs_error.h"
45 #include "xfs_vnodeops.h"
46
47 struct xfs_name xfs_name_dotdot = {"..", 2};
48
49 extern const struct xfs_nameops xfs_default_nameops;
50
51 void
52 xfs_dir_mount(
53         xfs_mount_t     *mp)
54 {
55         ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
56         ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
57                XFS_MAX_BLOCKSIZE);
58         mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
59         mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
60         mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
61         mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
62         mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
63         mp->m_attr_node_ents =
64                 (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
65                 (uint)sizeof(xfs_da_node_entry_t);
66         mp->m_dir_node_ents =
67                 (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
68                 (uint)sizeof(xfs_da_node_entry_t);
69         mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
70         mp->m_dirnameops = &xfs_default_nameops;
71 }
72
73 /*
74  * Return 1 if directory contains only "." and "..".
75  */
76 int
77 xfs_dir_isempty(
78         xfs_inode_t     *dp)
79 {
80         xfs_dir2_sf_t   *sfp;
81
82         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
83         if (dp->i_d.di_size == 0)       /* might happen during shutdown. */
84                 return 1;
85         if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
86                 return 0;
87         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
88         return !sfp->hdr.count;
89 }
90
91 /*
92  * Validate a given inode number.
93  */
94 int
95 xfs_dir_ino_validate(
96         xfs_mount_t     *mp,
97         xfs_ino_t       ino)
98 {
99         xfs_agblock_t   agblkno;
100         xfs_agino_t     agino;
101         xfs_agnumber_t  agno;
102         int             ino_ok;
103         int             ioff;
104
105         agno = XFS_INO_TO_AGNO(mp, ino);
106         agblkno = XFS_INO_TO_AGBNO(mp, ino);
107         ioff = XFS_INO_TO_OFFSET(mp, ino);
108         agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
109         ino_ok =
110                 agno < mp->m_sb.sb_agcount &&
111                 agblkno < mp->m_sb.sb_agblocks &&
112                 agblkno != 0 &&
113                 ioff < (1 << mp->m_sb.sb_inopblog) &&
114                 XFS_AGINO_TO_INO(mp, agno, agino) == ino;
115         if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
116                         XFS_RANDOM_DIR_INO_VALIDATE))) {
117                 xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
118                                 (unsigned long long) ino);
119                 XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
120                 return XFS_ERROR(EFSCORRUPTED);
121         }
122         return 0;
123 }
124
125 /*
126  * Initialize a directory with its "." and ".." entries.
127  */
128 int
129 xfs_dir_init(
130         xfs_trans_t     *tp,
131         xfs_inode_t     *dp,
132         xfs_inode_t     *pdp)
133 {
134         xfs_da_args_t   args;
135         int             error;
136
137         memset((char *)&args, 0, sizeof(args));
138         args.dp = dp;
139         args.trans = tp;
140         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
141         if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino)))
142                 return error;
143         return xfs_dir2_sf_create(&args, pdp->i_ino);
144 }
145
146 /*
147   Enter a name in a directory.
148  */
149 int
150 xfs_dir_createname(
151         xfs_trans_t             *tp,
152         xfs_inode_t             *dp,
153         struct xfs_name         *name,
154         xfs_ino_t               inum,           /* new entry inode number */
155         xfs_fsblock_t           *first,         /* bmap's firstblock */
156         xfs_bmap_free_t         *flist,         /* bmap's freeblock list */
157         xfs_extlen_t            total)          /* bmap's total block count */
158 {
159         xfs_da_args_t           args;
160         int                     rval;
161         int                     v;              /* type-checking value */
162
163         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
164         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
165                 return rval;
166         XFS_STATS_INC(xs_dir_create);
167
168         args.name = name->name;
169         args.namelen = name->len;
170         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
171         args.inumber = inum;
172         args.dp = dp;
173         args.firstblock = first;
174         args.flist = flist;
175         args.total = total;
176         args.whichfork = XFS_DATA_FORK;
177         args.trans = tp;
178         args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
179
180         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
181                 rval = xfs_dir2_sf_addname(&args);
182         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
183                 return rval;
184         else if (v)
185                 rval = xfs_dir2_block_addname(&args);
186         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
187                 return rval;
188         else if (v)
189                 rval = xfs_dir2_leaf_addname(&args);
190         else
191                 rval = xfs_dir2_node_addname(&args);
192         return rval;
193 }
194
195 /*
196  * Lookup a name in a directory, give back the inode number.
197  */
198 int
199 xfs_dir_lookup(
200         xfs_trans_t     *tp,
201         xfs_inode_t     *dp,
202         struct xfs_name *name,
203         xfs_ino_t       *inum)          /* out: inode number */
204 {
205         xfs_da_args_t   args;
206         int             rval;
207         int             v;              /* type-checking value */
208
209         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
210         XFS_STATS_INC(xs_dir_lookup);
211         memset(&args, 0, sizeof(xfs_da_args_t));
212
213         args.name = name->name;
214         args.namelen = name->len;
215         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
216         args.dp = dp;
217         args.whichfork = XFS_DATA_FORK;
218         args.trans = tp;
219         args.op_flags = XFS_DA_OP_OKNOENT;
220         args.cmpresult = XFS_CMP_DIFFERENT;
221
222         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
223                 rval = xfs_dir2_sf_lookup(&args);
224         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
225                 return rval;
226         else if (v)
227                 rval = xfs_dir2_block_lookup(&args);
228         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
229                 return rval;
230         else if (v)
231                 rval = xfs_dir2_leaf_lookup(&args);
232         else
233                 rval = xfs_dir2_node_lookup(&args);
234         if (rval == EEXIST)
235                 rval = 0;
236         if (rval == 0)
237                 *inum = args.inumber;
238         return rval;
239 }
240
241 /*
242  * Remove an entry from a directory.
243  */
244 int
245 xfs_dir_removename(
246         xfs_trans_t     *tp,
247         xfs_inode_t     *dp,
248         struct xfs_name *name,
249         xfs_ino_t       ino,
250         xfs_fsblock_t   *first,         /* bmap's firstblock */
251         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
252         xfs_extlen_t    total)          /* bmap's total block count */
253 {
254         xfs_da_args_t   args;
255         int             rval;
256         int             v;              /* type-checking value */
257
258         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
259         XFS_STATS_INC(xs_dir_remove);
260
261         args.name = name->name;
262         args.namelen = name->len;
263         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
264         args.inumber = ino;
265         args.dp = dp;
266         args.firstblock = first;
267         args.flist = flist;
268         args.total = total;
269         args.whichfork = XFS_DATA_FORK;
270         args.trans = tp;
271         args.op_flags = 0;
272
273         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
274                 rval = xfs_dir2_sf_removename(&args);
275         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
276                 return rval;
277         else if (v)
278                 rval = xfs_dir2_block_removename(&args);
279         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
280                 return rval;
281         else if (v)
282                 rval = xfs_dir2_leaf_removename(&args);
283         else
284                 rval = xfs_dir2_node_removename(&args);
285         return rval;
286 }
287
288 /*
289  * Read a directory.
290  */
291 int
292 xfs_readdir(
293         xfs_inode_t     *dp,
294         void            *dirent,
295         size_t          bufsize,
296         xfs_off_t       *offset,
297         filldir_t       filldir)
298 {
299         int             rval;           /* return value */
300         int             v;              /* type-checking value */
301
302         xfs_itrace_entry(dp);
303
304         if (XFS_FORCED_SHUTDOWN(dp->i_mount))
305                 return XFS_ERROR(EIO);
306
307         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
308         XFS_STATS_INC(xs_dir_getdents);
309
310         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
311                 rval = xfs_dir2_sf_getdents(dp, dirent, offset, filldir);
312         else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
313                 ;
314         else if (v)
315                 rval = xfs_dir2_block_getdents(dp, dirent, offset, filldir);
316         else
317                 rval = xfs_dir2_leaf_getdents(dp, dirent, bufsize, offset,
318                                               filldir);
319         return rval;
320 }
321
322 /*
323  * Replace the inode number of a directory entry.
324  */
325 int
326 xfs_dir_replace(
327         xfs_trans_t     *tp,
328         xfs_inode_t     *dp,
329         struct xfs_name *name,          /* name of entry to replace */
330         xfs_ino_t       inum,           /* new inode number */
331         xfs_fsblock_t   *first,         /* bmap's firstblock */
332         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
333         xfs_extlen_t    total)          /* bmap's total block count */
334 {
335         xfs_da_args_t   args;
336         int             rval;
337         int             v;              /* type-checking value */
338
339         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
340
341         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
342                 return rval;
343
344         args.name = name->name;
345         args.namelen = name->len;
346         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
347         args.inumber = inum;
348         args.dp = dp;
349         args.firstblock = first;
350         args.flist = flist;
351         args.total = total;
352         args.whichfork = XFS_DATA_FORK;
353         args.trans = tp;
354         args.op_flags = 0;
355
356         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
357                 rval = xfs_dir2_sf_replace(&args);
358         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
359                 return rval;
360         else if (v)
361                 rval = xfs_dir2_block_replace(&args);
362         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
363                 return rval;
364         else if (v)
365                 rval = xfs_dir2_leaf_replace(&args);
366         else
367                 rval = xfs_dir2_node_replace(&args);
368         return rval;
369 }
370
371 /*
372  * See if this entry can be added to the directory without allocating space.
373  * First checks that the caller couldn't reserve enough space (resblks = 0).
374  */
375 int
376 xfs_dir_canenter(
377         xfs_trans_t     *tp,
378         xfs_inode_t     *dp,
379         struct xfs_name *name,          /* name of entry to add */
380         uint            resblks)
381 {
382         xfs_da_args_t   args;
383         int             rval;
384         int             v;              /* type-checking value */
385
386         if (resblks)
387                 return 0;
388
389         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
390         memset(&args, 0, sizeof(xfs_da_args_t));
391
392         args.name = name->name;
393         args.namelen = name->len;
394         args.hashval = dp->i_mount->m_dirnameops->hashname(name);
395         args.dp = dp;
396         args.whichfork = XFS_DATA_FORK;
397         args.trans = tp;
398         args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
399                                                         XFS_DA_OP_OKNOENT;
400
401         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
402                 rval = xfs_dir2_sf_addname(&args);
403         else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
404                 return rval;
405         else if (v)
406                 rval = xfs_dir2_block_addname(&args);
407         else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
408                 return rval;
409         else if (v)
410                 rval = xfs_dir2_leaf_addname(&args);
411         else
412                 rval = xfs_dir2_node_addname(&args);
413         return rval;
414 }
415
416 /*
417  * Utility routines.
418  */
419
420 /*
421  * Add a block to the directory.
422  * This routine is for data and free blocks, not leaf/node blocks
423  * which are handled by xfs_da_grow_inode.
424  */
425 int
426 xfs_dir2_grow_inode(
427         xfs_da_args_t   *args,
428         int             space,          /* v2 dir's space XFS_DIR2_xxx_SPACE */
429         xfs_dir2_db_t   *dbp)           /* out: block number added */
430 {
431         xfs_fileoff_t   bno;            /* directory offset of new block */
432         int             count;          /* count of filesystem blocks */
433         xfs_inode_t     *dp;            /* incore directory inode */
434         int             error;
435         int             got;            /* blocks actually mapped */
436         int             i;
437         xfs_bmbt_irec_t map;            /* single structure for bmap */
438         int             mapi;           /* mapping index */
439         xfs_bmbt_irec_t *mapp;          /* bmap mapping structure(s) */
440         xfs_mount_t     *mp;
441         int             nmap;           /* number of bmap entries */
442         xfs_trans_t     *tp;
443
444         xfs_dir2_trace_args_s("grow_inode", args, space);
445         dp = args->dp;
446         tp = args->trans;
447         mp = dp->i_mount;
448         /*
449          * Set lowest possible block in the space requested.
450          */
451         bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
452         count = mp->m_dirblkfsbs;
453         /*
454          * Find the first hole for our block.
455          */
456         if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK)))
457                 return error;
458         nmap = 1;
459         ASSERT(args->firstblock != NULL);
460         /*
461          * Try mapping the new block contiguously (one extent).
462          */
463         if ((error = xfs_bmapi(tp, dp, bno, count,
464                         XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
465                         args->firstblock, args->total, &map, &nmap,
466                         args->flist, NULL)))
467                 return error;
468         ASSERT(nmap <= 1);
469         if (nmap == 1) {
470                 mapp = &map;
471                 mapi = 1;
472         }
473         /*
474          * Didn't work and this is a multiple-fsb directory block.
475          * Try again with contiguous flag turned on.
476          */
477         else if (nmap == 0 && count > 1) {
478                 xfs_fileoff_t   b;      /* current file offset */
479
480                 /*
481                  * Space for maximum number of mappings.
482                  */
483                 mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP);
484                 /*
485                  * Iterate until we get to the end of our block.
486                  */
487                 for (b = bno, mapi = 0; b < bno + count; ) {
488                         int     c;      /* current fsb count */
489
490                         /*
491                          * Can't map more than MAX_NMAP at once.
492                          */
493                         nmap = MIN(XFS_BMAP_MAX_NMAP, count);
494                         c = (int)(bno + count - b);
495                         if ((error = xfs_bmapi(tp, dp, b, c,
496                                         XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
497                                         args->firstblock, args->total,
498                                         &mapp[mapi], &nmap, args->flist,
499                                         NULL))) {
500                                 kmem_free(mapp);
501                                 return error;
502                         }
503                         if (nmap < 1)
504                                 break;
505                         /*
506                          * Add this bunch into our table, go to the next offset.
507                          */
508                         mapi += nmap;
509                         b = mapp[mapi - 1].br_startoff +
510                             mapp[mapi - 1].br_blockcount;
511                 }
512         }
513         /*
514          * Didn't work.
515          */
516         else {
517                 mapi = 0;
518                 mapp = NULL;
519         }
520         /*
521          * See how many fsb's we got.
522          */
523         for (i = 0, got = 0; i < mapi; i++)
524                 got += mapp[i].br_blockcount;
525         /*
526          * Didn't get enough fsb's, or the first/last block's are wrong.
527          */
528         if (got != count || mapp[0].br_startoff != bno ||
529             mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
530             bno + count) {
531                 if (mapp != &map)
532                         kmem_free(mapp);
533                 return XFS_ERROR(ENOSPC);
534         }
535         /*
536          * Done with the temporary mapping table.
537          */
538         if (mapp != &map)
539                 kmem_free(mapp);
540         *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
541         /*
542          * Update file's size if this is the data space and it grew.
543          */
544         if (space == XFS_DIR2_DATA_SPACE) {
545                 xfs_fsize_t     size;           /* directory file (data) size */
546
547                 size = XFS_FSB_TO_B(mp, bno + count);
548                 if (size > dp->i_d.di_size) {
549                         dp->i_d.di_size = size;
550                         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
551                 }
552         }
553         return 0;
554 }
555
556 /*
557  * See if the directory is a single-block form directory.
558  */
559 int
560 xfs_dir2_isblock(
561         xfs_trans_t     *tp,
562         xfs_inode_t     *dp,
563         int             *vp)            /* out: 1 is block, 0 is not block */
564 {
565         xfs_fileoff_t   last;           /* last file offset */
566         xfs_mount_t     *mp;
567         int             rval;
568
569         mp = dp->i_mount;
570         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
571                 return rval;
572         rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
573         ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
574         *vp = rval;
575         return 0;
576 }
577
578 /*
579  * See if the directory is a single-leaf form directory.
580  */
581 int
582 xfs_dir2_isleaf(
583         xfs_trans_t     *tp,
584         xfs_inode_t     *dp,
585         int             *vp)            /* out: 1 is leaf, 0 is not leaf */
586 {
587         xfs_fileoff_t   last;           /* last file offset */
588         xfs_mount_t     *mp;
589         int             rval;
590
591         mp = dp->i_mount;
592         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
593                 return rval;
594         *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
595         return 0;
596 }
597
598 /*
599  * Remove the given block from the directory.
600  * This routine is used for data and free blocks, leaf/node are done
601  * by xfs_da_shrink_inode.
602  */
603 int
604 xfs_dir2_shrink_inode(
605         xfs_da_args_t   *args,
606         xfs_dir2_db_t   db,
607         xfs_dabuf_t     *bp)
608 {
609         xfs_fileoff_t   bno;            /* directory file offset */
610         xfs_dablk_t     da;             /* directory file offset */
611         int             done;           /* bunmap is finished */
612         xfs_inode_t     *dp;
613         int             error;
614         xfs_mount_t     *mp;
615         xfs_trans_t     *tp;
616
617         xfs_dir2_trace_args_db("shrink_inode", args, db, bp);
618         dp = args->dp;
619         mp = dp->i_mount;
620         tp = args->trans;
621         da = xfs_dir2_db_to_da(mp, db);
622         /*
623          * Unmap the fsblock(s).
624          */
625         if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
626                         XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
627                         NULL, &done))) {
628                 /*
629                  * ENOSPC actually can happen if we're in a removename with
630                  * no space reservation, and the resulting block removal
631                  * would cause a bmap btree split or conversion from extents
632                  * to btree.  This can only happen for un-fragmented
633                  * directory blocks, since you need to be punching out
634                  * the middle of an extent.
635                  * In this case we need to leave the block in the file,
636                  * and not binval it.
637                  * So the block has to be in a consistent empty state
638                  * and appropriately logged.
639                  * We don't free up the buffer, the caller can tell it
640                  * hasn't happened since it got an error back.
641                  */
642                 return error;
643         }
644         ASSERT(done);
645         /*
646          * Invalidate the buffer from the transaction.
647          */
648         xfs_da_binval(tp, bp);
649         /*
650          * If it's not a data block, we're done.
651          */
652         if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
653                 return 0;
654         /*
655          * If the block isn't the last one in the directory, we're done.
656          */
657         if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0))
658                 return 0;
659         bno = da;
660         if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
661                 /*
662                  * This can't really happen unless there's kernel corruption.
663                  */
664                 return error;
665         }
666         if (db == mp->m_dirdatablk)
667                 ASSERT(bno == 0);
668         else
669                 ASSERT(bno > 0);
670         /*
671          * Set the size to the new last block.
672          */
673         dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
674         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
675         return 0;
676 }