Showing error 1667

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: fs/xfs/xfs_dir2.c
Line in file: 585
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 07:54:05 UTC


Source:

  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
 47struct xfs_name xfs_name_dotdot = {"..", 2};
 48
 49extern const struct xfs_nameops xfs_default_nameops;
 50
 51/*
 52 * ASCII case-insensitive (ie. A-Z) support for directories that was
 53 * used in IRIX.
 54 */
 55STATIC xfs_dahash_t
 56xfs_ascii_ci_hashname(
 57        struct xfs_name        *name)
 58{
 59        xfs_dahash_t        hash;
 60        int                i;
 61
 62        for (i = 0, hash = 0; i < name->len; i++)
 63                hash = tolower(name->name[i]) ^ rol32(hash, 7);
 64
 65        return hash;
 66}
 67
 68STATIC enum xfs_dacmp
 69xfs_ascii_ci_compname(
 70        struct xfs_da_args *args,
 71        const char        *name,
 72        int                 len)
 73{
 74        enum xfs_dacmp        result;
 75        int                i;
 76
 77        if (args->namelen != len)
 78                return XFS_CMP_DIFFERENT;
 79
 80        result = XFS_CMP_EXACT;
 81        for (i = 0; i < len; i++) {
 82                if (args->name[i] == name[i])
 83                        continue;
 84                if (tolower(args->name[i]) != tolower(name[i]))
 85                        return XFS_CMP_DIFFERENT;
 86                result = XFS_CMP_CASE;
 87        }
 88
 89        return result;
 90}
 91
 92static struct xfs_nameops xfs_ascii_ci_nameops = {
 93        .hashname        = xfs_ascii_ci_hashname,
 94        .compname        = xfs_ascii_ci_compname,
 95};
 96
 97void
 98xfs_dir_mount(
 99        xfs_mount_t        *mp)
100{
101        ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
102        ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
103               XFS_MAX_BLOCKSIZE);
104        mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
105        mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
106        mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
107        mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
108        mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
109        mp->m_attr_node_ents =
110                (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
111                (uint)sizeof(xfs_da_node_entry_t);
112        mp->m_dir_node_ents =
113                (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
114                (uint)sizeof(xfs_da_node_entry_t);
115        mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
116        if (xfs_sb_version_hasasciici(&mp->m_sb))
117                mp->m_dirnameops = &xfs_ascii_ci_nameops;
118        else
119                mp->m_dirnameops = &xfs_default_nameops;
120}
121
122/*
123 * Return 1 if directory contains only "." and "..".
124 */
125int
126xfs_dir_isempty(
127        xfs_inode_t        *dp)
128{
129        xfs_dir2_sf_t        *sfp;
130
131        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
132        if (dp->i_d.di_size == 0)        /* might happen during shutdown. */
133                return 1;
134        if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
135                return 0;
136        sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
137        return !sfp->hdr.count;
138}
139
140/*
141 * Validate a given inode number.
142 */
143int
144xfs_dir_ino_validate(
145        xfs_mount_t        *mp,
146        xfs_ino_t        ino)
147{
148        xfs_agblock_t        agblkno;
149        xfs_agino_t        agino;
150        xfs_agnumber_t        agno;
151        int                ino_ok;
152        int                ioff;
153
154        agno = XFS_INO_TO_AGNO(mp, ino);
155        agblkno = XFS_INO_TO_AGBNO(mp, ino);
156        ioff = XFS_INO_TO_OFFSET(mp, ino);
157        agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
158        ino_ok =
159                agno < mp->m_sb.sb_agcount &&
160                agblkno < mp->m_sb.sb_agblocks &&
161                agblkno != 0 &&
162                ioff < (1 << mp->m_sb.sb_inopblog) &&
163                XFS_AGINO_TO_INO(mp, agno, agino) == ino;
164        if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE,
165                        XFS_RANDOM_DIR_INO_VALIDATE))) {
166                xfs_fs_cmn_err(CE_WARN, mp, "Invalid inode number 0x%Lx",
167                                (unsigned long long) ino);
168                XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp);
169                return XFS_ERROR(EFSCORRUPTED);
170        }
171        return 0;
172}
173
174/*
175 * Initialize a directory with its "." and ".." entries.
176 */
177int
178xfs_dir_init(
179        xfs_trans_t        *tp,
180        xfs_inode_t        *dp,
181        xfs_inode_t        *pdp)
182{
183        xfs_da_args_t        args;
184        int                error;
185
186        memset((char *)&args, 0, sizeof(args));
187        args.dp = dp;
188        args.trans = tp;
189        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
190        if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino)))
191                return error;
192        return xfs_dir2_sf_create(&args, pdp->i_ino);
193}
194
195/*
196  Enter a name in a directory.
197 */
198int
199xfs_dir_createname(
200        xfs_trans_t                *tp,
201        xfs_inode_t                *dp,
202        struct xfs_name                *name,
203        xfs_ino_t                inum,                /* new entry inode number */
204        xfs_fsblock_t                *first,                /* bmap's firstblock */
205        xfs_bmap_free_t                *flist,                /* bmap's freeblock list */
206        xfs_extlen_t                total)                /* bmap's total block count */
207{
208        xfs_da_args_t                args;
209        int                        rval;
210        int                        v;                /* type-checking value */
211
212        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
213        if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
214                return rval;
215        XFS_STATS_INC(xs_dir_create);
216
217        memset(&args, 0, sizeof(xfs_da_args_t));
218        args.name = name->name;
219        args.namelen = name->len;
220        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
221        args.inumber = inum;
222        args.dp = dp;
223        args.firstblock = first;
224        args.flist = flist;
225        args.total = total;
226        args.whichfork = XFS_DATA_FORK;
227        args.trans = tp;
228        args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
229
230        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
231                rval = xfs_dir2_sf_addname(&args);
232        else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
233                return rval;
234        else if (v)
235                rval = xfs_dir2_block_addname(&args);
236        else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
237                return rval;
238        else if (v)
239                rval = xfs_dir2_leaf_addname(&args);
240        else
241                rval = xfs_dir2_node_addname(&args);
242        return rval;
243}
244
245/*
246 * If doing a CI lookup and case-insensitive match, dup actual name into
247 * args.value. Return EEXIST for success (ie. name found) or an error.
248 */
249int
250xfs_dir_cilookup_result(
251        struct xfs_da_args *args,
252        const char        *name,
253        int                len)
254{
255        if (args->cmpresult == XFS_CMP_DIFFERENT)
256                return ENOENT;
257        if (args->cmpresult != XFS_CMP_CASE ||
258                                        !(args->op_flags & XFS_DA_OP_CILOOKUP))
259                return EEXIST;
260
261        args->value = kmem_alloc(len, KM_MAYFAIL);
262        if (!args->value)
263                return ENOMEM;
264
265        memcpy(args->value, name, len);
266        args->valuelen = len;
267        return EEXIST;
268}
269
270/*
271 * Lookup a name in a directory, give back the inode number.
272 * If ci_name is not NULL, returns the actual name in ci_name if it differs
273 * to name, or ci_name->name is set to NULL for an exact match.
274 */
275
276int
277xfs_dir_lookup(
278        xfs_trans_t        *tp,
279        xfs_inode_t        *dp,
280        struct xfs_name        *name,
281        xfs_ino_t        *inum,                /* out: inode number */
282        struct xfs_name *ci_name)        /* out: actual name if CI match */
283{
284        xfs_da_args_t        args;
285        int                rval;
286        int                v;                /* type-checking value */
287
288        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
289        XFS_STATS_INC(xs_dir_lookup);
290
291        memset(&args, 0, sizeof(xfs_da_args_t));
292        args.name = name->name;
293        args.namelen = name->len;
294        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
295        args.dp = dp;
296        args.whichfork = XFS_DATA_FORK;
297        args.trans = tp;
298        args.op_flags = XFS_DA_OP_OKNOENT;
299        if (ci_name)
300                args.op_flags |= XFS_DA_OP_CILOOKUP;
301
302        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
303                rval = xfs_dir2_sf_lookup(&args);
304        else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
305                return rval;
306        else if (v)
307                rval = xfs_dir2_block_lookup(&args);
308        else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
309                return rval;
310        else if (v)
311                rval = xfs_dir2_leaf_lookup(&args);
312        else
313                rval = xfs_dir2_node_lookup(&args);
314        if (rval == EEXIST)
315                rval = 0;
316        if (!rval) {
317                *inum = args.inumber;
318                if (ci_name) {
319                        ci_name->name = args.value;
320                        ci_name->len = args.valuelen;
321                }
322        }
323        return rval;
324}
325
326/*
327 * Remove an entry from a directory.
328 */
329int
330xfs_dir_removename(
331        xfs_trans_t        *tp,
332        xfs_inode_t        *dp,
333        struct xfs_name        *name,
334        xfs_ino_t        ino,
335        xfs_fsblock_t        *first,                /* bmap's firstblock */
336        xfs_bmap_free_t        *flist,                /* bmap's freeblock list */
337        xfs_extlen_t        total)                /* bmap's total block count */
338{
339        xfs_da_args_t        args;
340        int                rval;
341        int                v;                /* type-checking value */
342
343        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
344        XFS_STATS_INC(xs_dir_remove);
345
346        memset(&args, 0, sizeof(xfs_da_args_t));
347        args.name = name->name;
348        args.namelen = name->len;
349        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
350        args.inumber = ino;
351        args.dp = dp;
352        args.firstblock = first;
353        args.flist = flist;
354        args.total = total;
355        args.whichfork = XFS_DATA_FORK;
356        args.trans = tp;
357
358        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
359                rval = xfs_dir2_sf_removename(&args);
360        else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
361                return rval;
362        else if (v)
363                rval = xfs_dir2_block_removename(&args);
364        else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
365                return rval;
366        else if (v)
367                rval = xfs_dir2_leaf_removename(&args);
368        else
369                rval = xfs_dir2_node_removename(&args);
370        return rval;
371}
372
373/*
374 * Read a directory.
375 */
376int
377xfs_readdir(
378        xfs_inode_t        *dp,
379        void                *dirent,
380        size_t                bufsize,
381        xfs_off_t        *offset,
382        filldir_t        filldir)
383{
384        int                rval;                /* return value */
385        int                v;                /* type-checking value */
386
387        xfs_itrace_entry(dp);
388
389        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
390                return XFS_ERROR(EIO);
391
392        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
393        XFS_STATS_INC(xs_dir_getdents);
394
395        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
396                rval = xfs_dir2_sf_getdents(dp, dirent, offset, filldir);
397        else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
398                ;
399        else if (v)
400                rval = xfs_dir2_block_getdents(dp, dirent, offset, filldir);
401        else
402                rval = xfs_dir2_leaf_getdents(dp, dirent, bufsize, offset,
403                                              filldir);
404        return rval;
405}
406
407/*
408 * Replace the inode number of a directory entry.
409 */
410int
411xfs_dir_replace(
412        xfs_trans_t        *tp,
413        xfs_inode_t        *dp,
414        struct xfs_name        *name,                /* name of entry to replace */
415        xfs_ino_t        inum,                /* new inode number */
416        xfs_fsblock_t        *first,                /* bmap's firstblock */
417        xfs_bmap_free_t        *flist,                /* bmap's freeblock list */
418        xfs_extlen_t        total)                /* bmap's total block count */
419{
420        xfs_da_args_t        args;
421        int                rval;
422        int                v;                /* type-checking value */
423
424        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
425
426        if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum)))
427                return rval;
428
429        memset(&args, 0, sizeof(xfs_da_args_t));
430        args.name = name->name;
431        args.namelen = name->len;
432        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
433        args.inumber = inum;
434        args.dp = dp;
435        args.firstblock = first;
436        args.flist = flist;
437        args.total = total;
438        args.whichfork = XFS_DATA_FORK;
439        args.trans = tp;
440
441        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
442                rval = xfs_dir2_sf_replace(&args);
443        else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
444                return rval;
445        else if (v)
446                rval = xfs_dir2_block_replace(&args);
447        else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
448                return rval;
449        else if (v)
450                rval = xfs_dir2_leaf_replace(&args);
451        else
452                rval = xfs_dir2_node_replace(&args);
453        return rval;
454}
455
456/*
457 * See if this entry can be added to the directory without allocating space.
458 * First checks that the caller couldn't reserve enough space (resblks = 0).
459 */
460int
461xfs_dir_canenter(
462        xfs_trans_t        *tp,
463        xfs_inode_t        *dp,
464        struct xfs_name        *name,                /* name of entry to add */
465        uint                resblks)
466{
467        xfs_da_args_t        args;
468        int                rval;
469        int                v;                /* type-checking value */
470
471        if (resblks)
472                return 0;
473
474        ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
475
476        memset(&args, 0, sizeof(xfs_da_args_t));
477        args.name = name->name;
478        args.namelen = name->len;
479        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
480        args.dp = dp;
481        args.whichfork = XFS_DATA_FORK;
482        args.trans = tp;
483        args.op_flags = XFS_DA_OP_JUSTCHECK | XFS_DA_OP_ADDNAME |
484                                                        XFS_DA_OP_OKNOENT;
485
486        if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
487                rval = xfs_dir2_sf_addname(&args);
488        else if ((rval = xfs_dir2_isblock(tp, dp, &v)))
489                return rval;
490        else if (v)
491                rval = xfs_dir2_block_addname(&args);
492        else if ((rval = xfs_dir2_isleaf(tp, dp, &v)))
493                return rval;
494        else if (v)
495                rval = xfs_dir2_leaf_addname(&args);
496        else
497                rval = xfs_dir2_node_addname(&args);
498        return rval;
499}
500
501/*
502 * Utility routines.
503 */
504
505/*
506 * Add a block to the directory.
507 * This routine is for data and free blocks, not leaf/node blocks
508 * which are handled by xfs_da_grow_inode.
509 */
510int
511xfs_dir2_grow_inode(
512        xfs_da_args_t        *args,
513        int                space,                /* v2 dir's space XFS_DIR2_xxx_SPACE */
514        xfs_dir2_db_t        *dbp)                /* out: block number added */
515{
516        xfs_fileoff_t        bno;                /* directory offset of new block */
517        int                count;                /* count of filesystem blocks */
518        xfs_inode_t        *dp;                /* incore directory inode */
519        int                error;
520        int                got;                /* blocks actually mapped */
521        int                i;
522        xfs_bmbt_irec_t        map;                /* single structure for bmap */
523        int                mapi;                /* mapping index */
524        xfs_bmbt_irec_t        *mapp;                /* bmap mapping structure(s) */
525        xfs_mount_t        *mp;
526        int                nmap;                /* number of bmap entries */
527        xfs_trans_t        *tp;
528        xfs_drfsbno_t        nblks;
529
530        xfs_dir2_trace_args_s("grow_inode", args, space);
531        dp = args->dp;
532        tp = args->trans;
533        mp = dp->i_mount;
534        nblks = dp->i_d.di_nblocks;
535        /*
536         * Set lowest possible block in the space requested.
537         */
538        bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
539        count = mp->m_dirblkfsbs;
540        /*
541         * Find the first hole for our block.
542         */
543        if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK)))
544                return error;
545        nmap = 1;
546        ASSERT(args->firstblock != NULL);
547        /*
548         * Try mapping the new block contiguously (one extent).
549         */
550        if ((error = xfs_bmapi(tp, dp, bno, count,
551                        XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
552                        args->firstblock, args->total, &map, &nmap,
553                        args->flist, NULL)))
554                return error;
555        ASSERT(nmap <= 1);
556        if (nmap == 1) {
557                mapp = &map;
558                mapi = 1;
559        }
560        /*
561         * Didn't work and this is a multiple-fsb directory block.
562         * Try again with contiguous flag turned on.
563         */
564        else if (nmap == 0 && count > 1) {
565                xfs_fileoff_t        b;        /* current file offset */
566
567                /*
568                 * Space for maximum number of mappings.
569                 */
570                mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP);
571                /*
572                 * Iterate until we get to the end of our block.
573                 */
574                for (b = bno, mapi = 0; b < bno + count; ) {
575                        int        c;        /* current fsb count */
576
577                        /*
578                         * Can't map more than MAX_NMAP at once.
579                         */
580                        nmap = MIN(XFS_BMAP_MAX_NMAP, count);
581                        c = (int)(bno + count - b);
582                        if ((error = xfs_bmapi(tp, dp, b, c,
583                                        XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
584                                        args->firstblock, args->total,
585                                        &mapp[mapi], &nmap, args->flist,
586                                        NULL))) {
587                                kmem_free(mapp);
588                                return error;
589                        }
590                        if (nmap < 1)
591                                break;
592                        /*
593                         * Add this bunch into our table, go to the next offset.
594                         */
595                        mapi += nmap;
596                        b = mapp[mapi - 1].br_startoff +
597                            mapp[mapi - 1].br_blockcount;
598                }
599        }
600        /*
601         * Didn't work.
602         */
603        else {
604                mapi = 0;
605                mapp = NULL;
606        }
607        /*
608         * See how many fsb's we got.
609         */
610        for (i = 0, got = 0; i < mapi; i++)
611                got += mapp[i].br_blockcount;
612        /*
613         * Didn't get enough fsb's, or the first/last block's are wrong.
614         */
615        if (got != count || mapp[0].br_startoff != bno ||
616            mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
617            bno + count) {
618                if (mapp != &map)
619                        kmem_free(mapp);
620                return XFS_ERROR(ENOSPC);
621        }
622        /*
623         * Done with the temporary mapping table.
624         */
625        if (mapp != &map)
626                kmem_free(mapp);
627
628        /* account for newly allocated blocks in reserved blocks total */
629        args->total -= dp->i_d.di_nblocks - nblks;
630        *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
631
632        /*
633         * Update file's size if this is the data space and it grew.
634         */
635        if (space == XFS_DIR2_DATA_SPACE) {
636                xfs_fsize_t        size;                /* directory file (data) size */
637
638                size = XFS_FSB_TO_B(mp, bno + count);
639                if (size > dp->i_d.di_size) {
640                        dp->i_d.di_size = size;
641                        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
642                }
643        }
644        return 0;
645}
646
647/*
648 * See if the directory is a single-block form directory.
649 */
650int
651xfs_dir2_isblock(
652        xfs_trans_t        *tp,
653        xfs_inode_t        *dp,
654        int                *vp)                /* out: 1 is block, 0 is not block */
655{
656        xfs_fileoff_t        last;                /* last file offset */
657        xfs_mount_t        *mp;
658        int                rval;
659
660        mp = dp->i_mount;
661        if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
662                return rval;
663        rval = XFS_FSB_TO_B(mp, last) == mp->m_dirblksize;
664        ASSERT(rval == 0 || dp->i_d.di_size == mp->m_dirblksize);
665        *vp = rval;
666        return 0;
667}
668
669/*
670 * See if the directory is a single-leaf form directory.
671 */
672int
673xfs_dir2_isleaf(
674        xfs_trans_t        *tp,
675        xfs_inode_t        *dp,
676        int                *vp)                /* out: 1 is leaf, 0 is not leaf */
677{
678        xfs_fileoff_t        last;                /* last file offset */
679        xfs_mount_t        *mp;
680        int                rval;
681
682        mp = dp->i_mount;
683        if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK)))
684                return rval;
685        *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
686        return 0;
687}
688
689/*
690 * Remove the given block from the directory.
691 * This routine is used for data and free blocks, leaf/node are done
692 * by xfs_da_shrink_inode.
693 */
694int
695xfs_dir2_shrink_inode(
696        xfs_da_args_t        *args,
697        xfs_dir2_db_t        db,
698        xfs_dabuf_t        *bp)
699{
700        xfs_fileoff_t        bno;                /* directory file offset */
701        xfs_dablk_t        da;                /* directory file offset */
702        int                done;                /* bunmap is finished */
703        xfs_inode_t        *dp;
704        int                error;
705        xfs_mount_t        *mp;
706        xfs_trans_t        *tp;
707
708        xfs_dir2_trace_args_db("shrink_inode", args, db, bp);
709        dp = args->dp;
710        mp = dp->i_mount;
711        tp = args->trans;
712        da = xfs_dir2_db_to_da(mp, db);
713        /*
714         * Unmap the fsblock(s).
715         */
716        if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
717                        XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
718                        NULL, &done))) {
719                /*
720                 * ENOSPC actually can happen if we're in a removename with
721                 * no space reservation, and the resulting block removal
722                 * would cause a bmap btree split or conversion from extents
723                 * to btree.  This can only happen for un-fragmented
724                 * directory blocks, since you need to be punching out
725                 * the middle of an extent.
726                 * In this case we need to leave the block in the file,
727                 * and not binval it.
728                 * So the block has to be in a consistent empty state
729                 * and appropriately logged.
730                 * We don't free up the buffer, the caller can tell it
731                 * hasn't happened since it got an error back.
732                 */
733                return error;
734        }
735        ASSERT(done);
736        /*
737         * Invalidate the buffer from the transaction.
738         */
739        xfs_da_binval(tp, bp);
740        /*
741         * If it's not a data block, we're done.
742         */
743        if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
744                return 0;
745        /*
746         * If the block isn't the last one in the directory, we're done.
747         */
748        if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0))
749                return 0;
750        bno = da;
751        if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
752                /*
753                 * This can't really happen unless there's kernel corruption.
754                 */
755                return error;
756        }
757        if (db == mp->m_dirdatablk)
758                ASSERT(bno == 0);
759        else
760                ASSERT(bno > 0);
761        /*
762         * Set the size to the new last block.
763         */
764        dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
765        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
766        return 0;
767}