]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/gnu/fs/xfs/xfs_dir2.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / gnu / 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_dir.h"
28 #include "xfs_dir2.h"
29 #include "xfs_dmapi.h"
30 #include "xfs_mount.h"
31 #include "xfs_da_btree.h"
32 #include "xfs_bmap_btree.h"
33 #include "xfs_alloc_btree.h"
34 #include "xfs_dir_sf.h"
35 #include "xfs_dir2_sf.h"
36 #include "xfs_attr_sf.h"
37 #include "xfs_dinode.h"
38 #include "xfs_inode.h"
39 #include "xfs_inode_item.h"
40 #include "xfs_bmap.h"
41 #include "xfs_dir_leaf.h"
42 #include "xfs_dir2_data.h"
43 #include "xfs_dir2_leaf.h"
44 #include "xfs_dir2_block.h"
45 #include "xfs_dir2_node.h"
46 #include "xfs_dir2_trace.h"
47 #include "xfs_error.h"
48
49 /*
50  * Declarations for interface routines.
51  */
52 static void     xfs_dir2_mount(xfs_mount_t *mp);
53 static int      xfs_dir2_isempty(xfs_inode_t *dp);
54 static int      xfs_dir2_init(xfs_trans_t *tp, xfs_inode_t *dp,
55                               xfs_inode_t *pdp);
56 static int      xfs_dir2_createname(xfs_trans_t *tp, xfs_inode_t *dp,
57                                     char *name, int namelen, xfs_ino_t inum,
58                                     xfs_fsblock_t *first,
59                                     xfs_bmap_free_t *flist, xfs_extlen_t total);
60 static int      xfs_dir2_lookup(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
61                                 int namelen, xfs_ino_t *inum);
62 static int      xfs_dir2_removename(xfs_trans_t *tp, xfs_inode_t *dp,
63                                     char *name, int namelen, xfs_ino_t ino,
64                                     xfs_fsblock_t *first,
65                                     xfs_bmap_free_t *flist, xfs_extlen_t total);
66 static int      xfs_dir2_getdents(xfs_trans_t *tp, xfs_inode_t *dp, uio_t *uio,
67                                   int *eofp);
68 static int      xfs_dir2_replace(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
69                                  int namelen, xfs_ino_t inum,
70                                  xfs_fsblock_t *first, xfs_bmap_free_t *flist,
71                                  xfs_extlen_t total);
72 static int      xfs_dir2_canenter(xfs_trans_t *tp, xfs_inode_t *dp, char *name,
73                                   int namelen);
74 static int      xfs_dir2_shortform_validate_ondisk(xfs_mount_t *mp,
75                                                    xfs_dinode_t *dip);
76
77 /*
78  * Utility routine declarations.
79  */
80 static int      xfs_dir2_put_dirent64_direct(xfs_dir2_put_args_t *pa);
81 static int      xfs_dir2_put_dirent64_uio(xfs_dir2_put_args_t *pa);
82
83 /*
84  * Directory operations vector.
85  */
86 xfs_dirops_t    xfsv2_dirops = {
87         .xd_mount                       = xfs_dir2_mount,
88         .xd_isempty                     = xfs_dir2_isempty,
89         .xd_init                        = xfs_dir2_init,
90         .xd_createname                  = xfs_dir2_createname,
91         .xd_lookup                      = xfs_dir2_lookup,
92         .xd_removename                  = xfs_dir2_removename,
93         .xd_getdents                    = xfs_dir2_getdents,
94         .xd_replace                     = xfs_dir2_replace,
95         .xd_canenter                    = xfs_dir2_canenter,
96         .xd_shortform_validate_ondisk   = xfs_dir2_shortform_validate_ondisk,
97         .xd_shortform_to_single         = xfs_dir2_sf_to_block,
98 };
99
100 /*
101  * Interface routines.
102  */
103
104 /*
105  * Initialize directory-related fields in the mount structure.
106  */
107 static void
108 xfs_dir2_mount(
109         xfs_mount_t     *mp)            /* filesystem mount point */
110 {
111         mp->m_dirversion = 2;
112         ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
113                XFS_MAX_BLOCKSIZE);
114         mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
115         mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
116         mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));
117         mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
118         mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));
119         mp->m_attr_node_ents =
120                 (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
121                 (uint)sizeof(xfs_da_node_entry_t);
122         mp->m_dir_node_ents =
123                 (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
124                 (uint)sizeof(xfs_da_node_entry_t);
125         mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
126 }
127
128 /*
129  * Return 1 if directory contains only "." and "..".
130  */
131 static int                              /* return code */
132 xfs_dir2_isempty(
133         xfs_inode_t     *dp)            /* incore inode structure */
134 {
135         xfs_dir2_sf_t   *sfp;           /* shortform directory structure */
136
137         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
138         /*
139          * Might happen during shutdown.
140          */
141         if (dp->i_d.di_size == 0) {
142                 return 1;
143         }
144         if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp))
145                 return 0;
146         sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
147         return !sfp->hdr.count;
148 }
149
150 /*
151  * Initialize a directory with its "." and ".." entries.
152  */
153 static int                              /* error */
154 xfs_dir2_init(
155         xfs_trans_t     *tp,            /* transaction pointer */
156         xfs_inode_t     *dp,            /* incore directory inode */
157         xfs_inode_t     *pdp)           /* incore parent directory inode */
158 {
159         xfs_da_args_t   args;           /* operation arguments */
160         int             error;          /* error return value */
161
162         memset((char *)&args, 0, sizeof(args));
163         args.dp = dp;
164         args.trans = tp;
165         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
166         if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) {
167                 return error;
168         }
169         return xfs_dir2_sf_create(&args, pdp->i_ino);
170 }
171
172 /*
173   Enter a name in a directory.
174  */
175 static int                                      /* error */
176 xfs_dir2_createname(
177         xfs_trans_t             *tp,            /* transaction pointer */
178         xfs_inode_t             *dp,            /* incore directory inode */
179         char                    *name,          /* new entry name */
180         int                     namelen,        /* new entry name length */
181         xfs_ino_t               inum,           /* new entry inode number */
182         xfs_fsblock_t           *first,         /* bmap's firstblock */
183         xfs_bmap_free_t         *flist,         /* bmap's freeblock list */
184         xfs_extlen_t            total)          /* bmap's total block count */
185 {
186         xfs_da_args_t           args;           /* operation arguments */
187         int                     rval;           /* return value */
188         int                     v;              /* type-checking value */
189
190         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
191         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
192                 return rval;
193         }
194         XFS_STATS_INC(xs_dir_create);
195         /*
196          * Fill in the arg structure for this request.
197          */
198         args.name = name;
199         args.namelen = namelen;
200         args.hashval = xfs_da_hashname(name, namelen);
201         args.inumber = inum;
202         args.dp = dp;
203         args.firstblock = first;
204         args.flist = flist;
205         args.total = total;
206         args.whichfork = XFS_DATA_FORK;
207         args.trans = tp;
208         args.justcheck = 0;
209         args.addname = args.oknoent = 1;
210         /*
211          * Decide on what work routines to call based on the inode size.
212          */
213         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
214                 rval = xfs_dir2_sf_addname(&args);
215         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
216                 return rval;
217         } else if (v)
218                 rval = xfs_dir2_block_addname(&args);
219         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
220                 return rval;
221         } else if (v)
222                 rval = xfs_dir2_leaf_addname(&args);
223         else
224                 rval = xfs_dir2_node_addname(&args);
225         return rval;
226 }
227
228 /*
229  * Lookup a name in a directory, give back the inode number.
230  */
231 static int                              /* error */
232 xfs_dir2_lookup(
233         xfs_trans_t     *tp,            /* transaction pointer */
234         xfs_inode_t     *dp,            /* incore directory inode */
235         char            *name,          /* lookup name */
236         int             namelen,        /* lookup name length */
237         xfs_ino_t       *inum)          /* out: inode number */
238 {
239         xfs_da_args_t   args;           /* operation arguments */
240         int             rval;           /* return value */
241         int             v;              /* type-checking value */
242
243         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
244         XFS_STATS_INC(xs_dir_lookup);
245
246         /*
247          * Fill in the arg structure for this request.
248          */
249         args.name = name;
250         args.namelen = namelen;
251         args.hashval = xfs_da_hashname(name, namelen);
252         args.inumber = 0;
253         args.dp = dp;
254         args.firstblock = NULL;
255         args.flist = NULL;
256         args.total = 0;
257         args.whichfork = XFS_DATA_FORK;
258         args.trans = tp;
259         args.justcheck = args.addname = 0;
260         args.oknoent = 1;
261         /*
262          * Decide on what work routines to call based on the inode size.
263          */
264         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
265                 rval = xfs_dir2_sf_lookup(&args);
266         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
267                 return rval;
268         } else if (v)
269                 rval = xfs_dir2_block_lookup(&args);
270         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
271                 return rval;
272         } else if (v)
273                 rval = xfs_dir2_leaf_lookup(&args);
274         else
275                 rval = xfs_dir2_node_lookup(&args);
276         if (rval == EEXIST)
277                 rval = 0;
278         if (rval == 0)
279                 *inum = args.inumber;
280         return rval;
281 }
282
283 /*
284  * Remove an entry from a directory.
285  */
286 static int                              /* error */
287 xfs_dir2_removename(
288         xfs_trans_t     *tp,            /* transaction pointer */
289         xfs_inode_t     *dp,            /* incore directory inode */
290         char            *name,          /* name of entry to remove */
291         int             namelen,        /* name length of entry to remove */
292         xfs_ino_t       ino,            /* inode number of entry to remove */
293         xfs_fsblock_t   *first,         /* bmap's firstblock */
294         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
295         xfs_extlen_t    total)          /* bmap's total block count */
296 {
297         xfs_da_args_t   args;           /* operation arguments */
298         int             rval;           /* return value */
299         int             v;              /* type-checking value */
300
301         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
302         XFS_STATS_INC(xs_dir_remove);
303         /*
304          * Fill in the arg structure for this request.
305          */
306         args.name = name;
307         args.namelen = namelen;
308         args.hashval = xfs_da_hashname(name, namelen);
309         args.inumber = ino;
310         args.dp = dp;
311         args.firstblock = first;
312         args.flist = flist;
313         args.total = total;
314         args.whichfork = XFS_DATA_FORK;
315         args.trans = tp;
316         args.justcheck = args.addname = args.oknoent = 0;
317         /*
318          * Decide on what work routines to call based on the inode size.
319          */
320         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
321                 rval = xfs_dir2_sf_removename(&args);
322         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
323                 return rval;
324         } else if (v)
325                 rval = xfs_dir2_block_removename(&args);
326         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
327                 return rval;
328         } else if (v)
329                 rval = xfs_dir2_leaf_removename(&args);
330         else
331                 rval = xfs_dir2_node_removename(&args);
332         return rval;
333 }
334
335 /*
336  * Read a directory.
337  */
338 static int                              /* error */
339 xfs_dir2_getdents(
340         xfs_trans_t     *tp,            /* transaction pointer */
341         xfs_inode_t     *dp,            /* incore directory inode */
342         uio_t           *uio,           /* caller's buffer control */
343         int             *eofp)          /* out: eof reached */
344 {
345         int             alignment;      /* alignment required for ABI */
346         xfs_dirent_t    *dbp;           /* malloc'ed buffer */
347         xfs_dir2_put_t  put;            /* entry formatting routine */
348         int             rval;           /* return value */
349         int             v;              /* type-checking value */
350
351         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
352         XFS_STATS_INC(xs_dir_getdents);
353         /*
354          * If our caller has given us a single contiguous aligned memory buffer,
355          * just work directly within that buffer.  If it's in user memory,
356          * lock it down first.
357          */
358         alignment = sizeof(xfs_off_t) - 1;
359         if ((uio->uio_iovcnt == 1) &&
360             (((__psint_t)uio->uio_iov[0].iov_base & alignment) == 0) &&
361             ((uio->uio_iov[0].iov_len & alignment) == 0)) {
362                 dbp = NULL;
363                 put = xfs_dir2_put_dirent64_direct;
364         } else {
365                 dbp = kmem_alloc(sizeof(*dbp) + MAXNAMELEN, KM_SLEEP);
366                 put = xfs_dir2_put_dirent64_uio;
367         }
368
369         *eofp = 0;
370         /*
371          * Decide on what work routines to call based on the inode size.
372          */
373         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
374                 rval = xfs_dir2_sf_getdents(dp, uio, eofp, dbp, put);
375         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
376                 ;
377         } else if (v)
378                 rval = xfs_dir2_block_getdents(tp, dp, uio, eofp, dbp, put);
379         else
380                 rval = xfs_dir2_leaf_getdents(tp, dp, uio, eofp, dbp, put);
381         if (dbp != NULL)
382                 kmem_free(dbp, sizeof(*dbp) + MAXNAMELEN);
383         return rval;
384 }
385
386 /*
387  * Replace the inode number of a directory entry.
388  */
389 static int                              /* error */
390 xfs_dir2_replace(
391         xfs_trans_t     *tp,            /* transaction pointer */
392         xfs_inode_t     *dp,            /* incore directory inode */
393         char            *name,          /* name of entry to replace */
394         int             namelen,        /* name length of entry to replace */
395         xfs_ino_t       inum,           /* new inode number */
396         xfs_fsblock_t   *first,         /* bmap's firstblock */
397         xfs_bmap_free_t *flist,         /* bmap's freeblock list */
398         xfs_extlen_t    total)          /* bmap's total block count */
399 {
400         xfs_da_args_t   args;           /* operation arguments */
401         int             rval;           /* return value */
402         int             v;              /* type-checking value */
403
404         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
405
406         if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) {
407                 return rval;
408         }
409         /*
410          * Fill in the arg structure for this request.
411          */
412         args.name = name;
413         args.namelen = namelen;
414         args.hashval = xfs_da_hashname(name, namelen);
415         args.inumber = inum;
416         args.dp = dp;
417         args.firstblock = first;
418         args.flist = flist;
419         args.total = total;
420         args.whichfork = XFS_DATA_FORK;
421         args.trans = tp;
422         args.justcheck = args.addname = args.oknoent = 0;
423         /*
424          * Decide on what work routines to call based on the inode size.
425          */
426         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
427                 rval = xfs_dir2_sf_replace(&args);
428         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
429                 return rval;
430         } else if (v)
431                 rval = xfs_dir2_block_replace(&args);
432         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
433                 return rval;
434         } else if (v)
435                 rval = xfs_dir2_leaf_replace(&args);
436         else
437                 rval = xfs_dir2_node_replace(&args);
438         return rval;
439 }
440
441 /*
442  * See if this entry can be added to the directory without allocating space.
443  */
444 static int                              /* error */
445 xfs_dir2_canenter(
446         xfs_trans_t     *tp,            /* transaction pointer */
447         xfs_inode_t     *dp,            /* incore directory inode */
448         char            *name,          /* name of entry to add */
449         int             namelen)        /* name length of entry to add */
450 {
451         xfs_da_args_t   args;           /* operation arguments */
452         int             rval;           /* return value */
453         int             v;              /* type-checking value */
454
455         ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR);
456         /*
457          * Fill in the arg structure for this request.
458          */
459         args.name = name;
460         args.namelen = namelen;
461         args.hashval = xfs_da_hashname(name, namelen);
462         args.inumber = 0;
463         args.dp = dp;
464         args.firstblock = NULL;
465         args.flist = NULL;
466         args.total = 0;
467         args.whichfork = XFS_DATA_FORK;
468         args.trans = tp;
469         args.justcheck = args.addname = args.oknoent = 1;
470         /*
471          * Decide on what work routines to call based on the inode size.
472          */
473         if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
474                 rval = xfs_dir2_sf_addname(&args);
475         else if ((rval = xfs_dir2_isblock(tp, dp, &v))) {
476                 return rval;
477         } else if (v)
478                 rval = xfs_dir2_block_addname(&args);
479         else if ((rval = xfs_dir2_isleaf(tp, dp, &v))) {
480                 return rval;
481         } else if (v)
482                 rval = xfs_dir2_leaf_addname(&args);
483         else
484                 rval = xfs_dir2_node_addname(&args);
485         return rval;
486 }
487
488 /*
489  * Dummy routine for shortform inode validation.
490  * Can't really do this.
491  */
492 /* ARGSUSED */
493 static int                              /* error */
494 xfs_dir2_shortform_validate_ondisk(
495         xfs_mount_t     *mp,            /* filesystem mount point */
496         xfs_dinode_t    *dip)           /* ondisk inode */
497 {
498         return 0;
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  */
510 int                                     /* error */
511 xfs_dir2_grow_inode(
512         xfs_da_args_t   *args,          /* operation arguments */
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;          /* error return value */
520         int             got;            /* blocks actually mapped */
521         int             i;              /* temp mapping index */
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;            /* filesystem mount point */
526         int             nmap;           /* number of bmap entries */
527         xfs_trans_t     *tp;            /* transaction pointer */
528
529         xfs_dir2_trace_args_s("grow_inode", args, space);
530         dp = args->dp;
531         tp = args->trans;
532         mp = dp->i_mount;
533         /*
534          * Set lowest possible block in the space requested.
535          */
536         bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE);
537         count = mp->m_dirblkfsbs;
538         /*
539          * Find the first hole for our block.
540          */
541         if ((error = xfs_bmap_first_unused(tp, dp, count, &bno, XFS_DATA_FORK))) {
542                 return error;
543         }
544         nmap = 1;
545         ASSERT(args->firstblock != NULL);
546         /*
547          * Try mapping the new block contiguously (one extent).
548          */
549         if ((error = xfs_bmapi(tp, dp, bno, count,
550                         XFS_BMAPI_WRITE|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG,
551                         args->firstblock, args->total, &map, &nmap,
552                         args->flist, NULL))) {
553                 return error;
554         }
555         ASSERT(nmap <= 1);
556         /*
557          * Got it in 1.
558          */
559         if (nmap == 1) {
560                 mapp = &map;
561                 mapi = 1;
562         }
563         /*
564          * Didn't work and this is a multiple-fsb directory block.
565          * Try again with contiguous flag turned on.
566          */
567         else if (nmap == 0 && count > 1) {
568                 xfs_fileoff_t   b;      /* current file offset */
569
570                 /*
571                  * Space for maximum number of mappings.
572                  */
573                 mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP);
574                 /*
575                  * Iterate until we get to the end of our block.
576                  */
577                 for (b = bno, mapi = 0; b < bno + count; ) {
578                         int     c;      /* current fsb count */
579
580                         /*
581                          * Can't map more than MAX_NMAP at once.
582                          */
583                         nmap = MIN(XFS_BMAP_MAX_NMAP, count);
584                         c = (int)(bno + count - b);
585                         if ((error = xfs_bmapi(tp, dp, b, c,
586                                         XFS_BMAPI_WRITE|XFS_BMAPI_METADATA,
587                                         args->firstblock, args->total,
588                                         &mapp[mapi], &nmap, args->flist,
589                                         NULL))) {
590                                 kmem_free(mapp, sizeof(*mapp) * count);
591                                 return error;
592                         }
593                         if (nmap < 1)
594                                 break;
595                         /*
596                          * Add this bunch into our table, go to the next offset.
597                          */
598                         mapi += nmap;
599                         b = mapp[mapi - 1].br_startoff +
600                             mapp[mapi - 1].br_blockcount;
601                 }
602         }
603         /*
604          * Didn't work.
605          */
606         else {
607                 mapi = 0;
608                 mapp = NULL;
609         }
610         /*
611          * See how many fsb's we got.
612          */
613         for (i = 0, got = 0; i < mapi; i++)
614                 got += mapp[i].br_blockcount;
615         /*
616          * Didn't get enough fsb's, or the first/last block's are wrong.
617          */
618         if (got != count || mapp[0].br_startoff != bno ||
619             mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount !=
620             bno + count) {
621                 if (mapp != &map)
622                         kmem_free(mapp, sizeof(*mapp) * count);
623                 return XFS_ERROR(ENOSPC);
624         }
625         /*
626          * Done with the temporary mapping table.
627          */
628         if (mapp != &map)
629                 kmem_free(mapp, sizeof(*mapp) * count);
630         *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno);
631         /*
632          * Update file's size if this is the data space and it grew.
633          */
634         if (space == XFS_DIR2_DATA_SPACE) {
635                 xfs_fsize_t     size;           /* directory file (data) size */
636
637                 size = XFS_FSB_TO_B(mp, bno + count);
638                 if (size > dp->i_d.di_size) {
639                         dp->i_d.di_size = size;
640                         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
641                 }
642         }
643         return 0;
644 }
645
646 /*
647  * See if the directory is a single-block form directory.
648  */
649 int                                     /* error */
650 xfs_dir2_isblock(
651         xfs_trans_t     *tp,            /* transaction pointer */
652         xfs_inode_t     *dp,            /* incore directory inode */
653         int             *vp)            /* out: 1 is block, 0 is not block */
654 {
655         xfs_fileoff_t   last;           /* last file offset */
656         xfs_mount_t     *mp;            /* filesystem mount point */
657         int             rval;           /* return value */
658
659         mp = dp->i_mount;
660         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
661                 return rval;
662         }
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  */
672 int                                     /* error */
673 xfs_dir2_isleaf(
674         xfs_trans_t     *tp,            /* transaction pointer */
675         xfs_inode_t     *dp,            /* incore directory inode */
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;            /* filesystem mount point */
680         int             rval;           /* return value */
681
682         mp = dp->i_mount;
683         if ((rval = xfs_bmap_last_offset(tp, dp, &last, XFS_DATA_FORK))) {
684                 return rval;
685         }
686         *vp = last == mp->m_dirleafblk + (1 << mp->m_sb.sb_dirblklog);
687         return 0;
688 }
689
690 /*
691  * Getdents put routine for 64-bit ABI, direct form.
692  */
693 static int                                      /* error */
694 xfs_dir2_put_dirent64_direct(
695         xfs_dir2_put_args_t     *pa)            /* argument bundle */
696 {
697         struct dirent           *idbp, dtmp;    /* dirent pointer */
698         iovec_t                 *iovp;          /* io vector */
699         int                     namelen;        /* entry name length */
700         int                     reclen;         /* entry total length */
701         uio_t                   *uio;           /* I/O control */
702
703         namelen = pa->namelen;
704
705         dtmp.d_namlen = namelen;
706         dtmp.d_reclen = GENERIC_DIRSIZ(&dtmp);
707         reclen = dtmp.d_reclen;
708
709         uio = pa->uio;
710         /*
711          * Won't fit in the remaining space.
712          */
713         if (reclen > uio->uio_resid) {
714                 pa->done = 0;
715                 return 0;
716         }
717         iovp = uio->uio_iov;
718         idbp = (struct dirent *)iovp->iov_base;
719         iovp->iov_base = (char *)idbp + reclen;
720         iovp->iov_len -= reclen;
721         uio->uio_resid -= reclen;
722         idbp->d_reclen = reclen;
723         idbp->d_fileno = pa->ino;
724         idbp->d_type = DT_UNKNOWN;
725         idbp->d_namlen = namelen;
726         memcpy(idbp->d_name, pa->name, namelen);
727         idbp->d_name[namelen] = '\0';
728         pa->done = 1;
729         return 0;
730 }
731
732 /*
733  * Getdents put routine for 64-bit ABI, uio form.
734  */
735 static int                                      /* error */
736 xfs_dir2_put_dirent64_uio(
737         xfs_dir2_put_args_t     *pa)            /* argument bundle */
738 {
739         struct dirent           *idbp, dtmp;    /* dirent pointer */
740         int                     namelen;        /* entry name length */
741         int                     reclen;         /* entry total length */
742         int                     rval;           /* return value */
743         uio_t                   *uio;           /* I/O control */
744
745         namelen = pa->namelen;
746
747         dtmp.d_namlen = namelen;
748         dtmp.d_reclen = GENERIC_DIRSIZ(&dtmp);
749         reclen = dtmp.d_reclen;
750
751         uio = pa->uio;
752         /*
753          * Won't fit in the remaining space.
754          */
755         if (reclen > uio->uio_resid) {
756                 pa->done = 0;
757                 return 0;
758         }
759         idbp = &dtmp;
760         idbp->d_reclen = reclen;
761         idbp->d_fileno = pa->ino;
762         idbp->d_type = DT_UNKNOWN;
763         idbp->d_namlen = namelen;
764         memcpy(idbp->d_name, pa->name, namelen);
765         idbp->d_name[namelen] = '\0';
766         rval = uio_read((caddr_t)idbp, reclen, uio);
767         pa->done = (rval == 0);
768         return rval;
769 }
770
771 /*
772  * Remove the given block from the directory.
773  * This routine is used for data and free blocks, leaf/node are done
774  * by xfs_da_shrink_inode.
775  */
776 int
777 xfs_dir2_shrink_inode(
778         xfs_da_args_t   *args,          /* operation arguments */
779         xfs_dir2_db_t   db,             /* directory block number */
780         xfs_dabuf_t     *bp)            /* block's buffer */
781 {
782         xfs_fileoff_t   bno;            /* directory file offset */
783         xfs_dablk_t     da;             /* directory file offset */
784         int             done;           /* bunmap is finished */
785         xfs_inode_t     *dp;            /* incore directory inode */
786         int             error;          /* error return value */
787         xfs_mount_t     *mp;            /* filesystem mount point */
788         xfs_trans_t     *tp;            /* transaction pointer */
789
790         xfs_dir2_trace_args_db("shrink_inode", args, db, bp);
791         dp = args->dp;
792         mp = dp->i_mount;
793         tp = args->trans;
794         da = XFS_DIR2_DB_TO_DA(mp, db);
795         /*
796          * Unmap the fsblock(s).
797          */
798         if ((error = xfs_bunmapi(tp, dp, da, mp->m_dirblkfsbs,
799                         XFS_BMAPI_METADATA, 0, args->firstblock, args->flist,
800                         NULL, &done))) {
801                 /*
802                  * ENOSPC actually can happen if we're in a removename with
803                  * no space reservation, and the resulting block removal
804                  * would cause a bmap btree split or conversion from extents
805                  * to btree.  This can only happen for un-fragmented
806                  * directory blocks, since you need to be punching out
807                  * the middle of an extent.
808                  * In this case we need to leave the block in the file,
809                  * and not binval it.
810                  * So the block has to be in a consistent empty state
811                  * and appropriately logged.
812                  * We don't free up the buffer, the caller can tell it
813                  * hasn't happened since it got an error back.
814                  */
815                 return error;
816         }
817         ASSERT(done);
818         /*
819          * Invalidate the buffer from the transaction.
820          */
821         xfs_da_binval(tp, bp);
822         /*
823          * If it's not a data block, we're done.
824          */
825         if (db >= XFS_DIR2_LEAF_FIRSTDB(mp))
826                 return 0;
827         /*
828          * If the block isn't the last one in the directory, we're done.
829          */
830         if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0))
831                 return 0;
832         bno = da;
833         if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
834                 /*
835                  * This can't really happen unless there's kernel corruption.
836                  */
837                 return error;
838         }
839         if (db == mp->m_dirdatablk)
840                 ASSERT(bno == 0);
841         else
842                 ASSERT(bno > 0);
843         /*
844          * Set the size to the new last block.
845          */
846         dp->i_d.di_size = XFS_FSB_TO_B(mp, bno);
847         xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
848         return 0;
849 }
850
851