]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/cddl/contrib/opensolaris/uts/common/fs/gfs.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / cddl / contrib / opensolaris / uts / common / fs / gfs.c
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /* Portions Copyright 2007 Shivakumar GN */
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26
27 #pragma ident   "%Z%%M% %I%     %E% SMI"
28
29 #include <sys/types.h>
30 #include <sys/cmn_err.h>
31 #include <sys/debug.h>
32 #include <sys/dirent.h>
33 #include <sys/kmem.h>
34 #include <sys/mman.h>
35 #include <sys/mutex.h>
36 #include <sys/sysmacros.h>
37 #include <sys/systm.h>
38 #include <sys/uio.h>
39 #include <sys/vfs.h>
40 #include <sys/vnode.h>
41 #include <sys/cred.h>
42 #include <sys/kdb.h>
43
44 #include <sys/gfs.h>
45
46 /*
47  * Generic pseudo-filesystem routines.
48  *
49  * There are significant similarities between the implementation of certain file
50  * system entry points across different filesystems.  While one could attempt to
51  * "choke up on the bat" and incorporate common functionality into a VOP
52  * preamble or postamble, such an approach is limited in the benefit it can
53  * provide.  In this file we instead define a toolkit of routines which can be
54  * called from a filesystem (with in-kernel pseudo-filesystems being the focus
55  * of the exercise) in a more component-like fashion.
56  *
57  * There are three basic classes of routines:
58  *
59  * 1) Lowlevel support routines
60  *
61  *    These routines are designed to play a support role for existing
62  *    pseudo-filesystems (such as procfs).  They simplify common tasks,
63  *    without enforcing the filesystem to hand over management to GFS.  The
64  *    routines covered are:
65  *
66  *      gfs_readdir_init()
67  *      gfs_readdir_emit()
68  *      gfs_readdir_emitn()
69  *      gfs_readdir_pred()
70  *      gfs_readdir_fini()
71  *      gfs_lookup_dot()
72  *
73  * 2) Complete GFS management
74  *
75  *    These routines take a more active role in management of the
76  *    pseudo-filesystem.  They handle the relationship between vnode private
77  *    data and VFS data, as well as the relationship between vnodes in the
78  *    directory hierarchy.
79  *
80  *    In order to use these interfaces, the first member of every private
81  *    v_data must be a gfs_file_t or a gfs_dir_t.  This hands over all control
82  *    to GFS.
83  *
84  *      gfs_file_create()
85  *      gfs_dir_create()
86  *      gfs_root_create()
87  *
88  *      gfs_file_inactive()
89  *      gfs_dir_inactive()
90  *      gfs_dir_lookup()
91  *      gfs_dir_readdir()
92  *
93  *      gfs_vop_inactive()
94  *      gfs_vop_lookup()
95  *      gfs_vop_readdir()
96  *      gfs_vop_map()
97  *
98  * 3) Single File pseudo-filesystems
99  *
100  *    This routine creates a rooted file to be overlayed ontop of another
101  *    file in the physical filespace.
102  *
103  *    Note that the parent is NULL (actually the vfs), but there is nothing
104  *    technically keeping such a file from utilizing the "Complete GFS
105  *    management" set of routines.
106  *
107  *      gfs_root_create_file()
108  */
109
110 /*
111  * Low level directory routines
112  *
113  * These routines provide some simple abstractions for reading directories.
114  * They are designed to be used by existing pseudo filesystems (namely procfs)
115  * that already have a complicated management infrastructure.
116  */
117
118 /*
119  * gfs_readdir_init: initiate a generic readdir
120  *   st         - a pointer to an uninitialized gfs_readdir_state_t structure
121  *   name_max   - the directory's maximum file name length
122  *   ureclen    - the exported file-space record length (1 for non-legacy FSs)
123  *   uiop       - the uiop passed to readdir
124  *   parent     - the parent directory's inode
125  *   self       - this directory's inode
126  *
127  * Returns 0 or a non-zero errno.
128  *
129  * Typical VOP_READDIR usage of gfs_readdir_*:
130  *
131  *      if ((error = gfs_readdir_init(...)) != 0)
132  *              return (error);
133  *      eof = 0;
134  *      while ((error = gfs_readdir_pred(..., &voffset)) != 0) {
135  *              if (!consumer_entry_at(voffset))
136  *                      voffset = consumer_next_entry(voffset);
137  *              if (consumer_eof(voffset)) {
138  *                      eof = 1
139  *                      break;
140  *              }
141  *              if ((error = gfs_readdir_emit(..., voffset,
142  *                  consumer_ino(voffset), consumer_name(voffset))) != 0)
143  *                      break;
144  *      }
145  *      return (gfs_readdir_fini(..., error, eofp, eof));
146  *
147  * As you can see, a zero result from gfs_readdir_pred() or
148  * gfs_readdir_emit() indicates that processing should continue,
149  * whereas a non-zero result indicates that the loop should terminate.
150  * Most consumers need do nothing more than let gfs_readdir_fini()
151  * determine what the cause of failure was and return the appropriate
152  * value.
153  */
154 int
155 gfs_readdir_init(gfs_readdir_state_t *st, int name_max, int ureclen,
156     uio_t *uiop, ino64_t parent, ino64_t self)
157 {
158         if (uiop->uio_loffset < 0 || uiop->uio_resid <= 0 ||
159             (uiop->uio_loffset % ureclen) != 0)
160                 return (EINVAL);
161
162         st->grd_ureclen = ureclen;
163         st->grd_oresid = uiop->uio_resid;
164         st->grd_namlen = name_max;
165         st->grd_dirent = kmem_zalloc(DIRENT64_RECLEN(st->grd_namlen), KM_SLEEP);
166         st->grd_parent = parent;
167         st->grd_self = self;
168
169         return (0);
170 }
171
172 /*
173  * gfs_readdir_emit_int: internal routine to emit directory entry
174  *
175  *   st         - the current readdir state, which must have d_ino and d_name
176  *                set
177  *   uiop       - caller-supplied uio pointer
178  *   next       - the offset of the next entry
179  */
180 static int
181 gfs_readdir_emit_int(gfs_readdir_state_t *st, uio_t *uiop, offset_t next,
182     int *ncookies, u_long **cookies)
183 {
184         int reclen, namlen;
185
186         namlen = strlen(st->grd_dirent->d_name);
187         reclen = DIRENT64_RECLEN(namlen);
188
189         if (reclen > uiop->uio_resid) {
190                 /*
191                  * Error if no entries were returned yet
192                  */
193                 if (uiop->uio_resid == st->grd_oresid)
194                         return (EINVAL);
195                 return (-1);
196         }
197
198         /* XXX: This can change in the future. */
199         st->grd_dirent->d_type = DT_DIR;
200         st->grd_dirent->d_reclen = (ushort_t)reclen;
201         st->grd_dirent->d_namlen = namlen;
202
203         if (uiomove((caddr_t)st->grd_dirent, reclen, UIO_READ, uiop))
204                 return (EFAULT);
205
206         uiop->uio_loffset = next;
207         if (*cookies != NULL) {
208                 **cookies = next;
209                 (*cookies)++;
210                 (*ncookies)--;
211                 KASSERT(*ncookies >= 0, ("ncookies=%d", *ncookies));
212         }
213
214         return (0);
215 }
216
217 /*
218  * gfs_readdir_emit: emit a directory entry
219  *   voff       - the virtual offset (obtained from gfs_readdir_pred)
220  *   ino        - the entry's inode
221  *   name       - the entry's name
222  *
223  * Returns a 0 on success, a non-zero errno on failure, or -1 if the
224  * readdir loop should terminate.  A non-zero result (either errno or
225  * -1) from this function is typically passed directly to
226  * gfs_readdir_fini().
227  */
228 int
229 gfs_readdir_emit(gfs_readdir_state_t *st, uio_t *uiop, offset_t voff,
230     ino64_t ino, const char *name, int *ncookies, u_long **cookies)
231 {
232         offset_t off = (voff + 2) * st->grd_ureclen;
233
234         st->grd_dirent->d_ino = ino;
235         (void) strncpy(st->grd_dirent->d_name, name, st->grd_namlen);
236
237         /*
238          * Inter-entry offsets are invalid, so we assume a record size of
239          * grd_ureclen and explicitly set the offset appropriately.
240          */
241         return (gfs_readdir_emit_int(st, uiop, off + st->grd_ureclen, ncookies,
242             cookies));
243 }
244
245 /*
246  * gfs_readdir_pred: readdir loop predicate
247  *   voffp - a pointer in which the next virtual offset should be stored
248  *
249  * Returns a 0 on success, a non-zero errno on failure, or -1 if the
250  * readdir loop should terminate.  A non-zero result (either errno or
251  * -1) from this function is typically passed directly to
252  * gfs_readdir_fini().
253  */
254 int
255 gfs_readdir_pred(gfs_readdir_state_t *st, uio_t *uiop, offset_t *voffp,
256     int *ncookies, u_long **cookies)
257 {
258         offset_t off, voff;
259         int error;
260
261 top:
262         if (uiop->uio_resid <= 0)
263                 return (-1);
264
265         off = uiop->uio_loffset / st->grd_ureclen;
266         voff = off - 2;
267         if (off == 0) {
268                 if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_self,
269                     ".", ncookies, cookies)) == 0)
270                         goto top;
271         } else if (off == 1) {
272                 if ((error = gfs_readdir_emit(st, uiop, voff, st->grd_parent,
273                     "..", ncookies, cookies)) == 0)
274                         goto top;
275         } else {
276                 *voffp = voff;
277                 return (0);
278         }
279
280         return (error);
281 }
282
283 /*
284  * gfs_readdir_fini: generic readdir cleanup
285  *   error      - if positive, an error to return
286  *   eofp       - the eofp passed to readdir
287  *   eof        - the eof value
288  *
289  * Returns a 0 on success, a non-zero errno on failure.  This result
290  * should be returned from readdir.
291  */
292 int
293 gfs_readdir_fini(gfs_readdir_state_t *st, int error, int *eofp, int eof)
294 {
295         kmem_free(st->grd_dirent, DIRENT64_RECLEN(st->grd_namlen));
296         if (error > 0)
297                 return (error);
298         if (eofp)
299                 *eofp = eof;
300         return (0);
301 }
302
303 /*
304  * gfs_lookup_dot
305  *
306  * Performs a basic check for "." and ".." directory entries.
307  */
308 int
309 gfs_lookup_dot(vnode_t **vpp, vnode_t *dvp, vnode_t *pvp, const char *nm)
310 {
311         if (*nm == '\0' || strcmp(nm, ".") == 0) {
312                 VN_HOLD(dvp);
313                 *vpp = dvp;
314                 return (0);
315         } else if (strcmp(nm, "..") == 0) {
316                 if (pvp == NULL) {
317                         ASSERT(dvp->v_flag & VROOT);
318                         VN_HOLD(dvp);
319                         *vpp = dvp;
320                 } else {
321                         VN_HOLD(pvp);
322                         *vpp = pvp;
323                 }
324                 vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, curthread);
325                 return (0);
326         }
327
328         return (-1);
329 }
330
331 /*
332  * gfs_file_create(): create a new GFS file
333  *
334  *   size       - size of private data structure (v_data)
335  *   pvp        - parent vnode (GFS directory)
336  *   ops        - vnode operations vector
337  *
338  * In order to use this interface, the parent vnode must have been created by
339  * gfs_dir_create(), and the private data stored in v_data must have a
340  * 'gfs_file_t' as its first field.
341  *
342  * Given these constraints, this routine will automatically:
343  *
344  *      - Allocate v_data for the vnode
345  *      - Initialize necessary fields in the vnode
346  *      - Hold the parent
347  */
348 vnode_t *
349 gfs_file_create(size_t size, vnode_t *pvp, vfs_t *vfsp, vnodeops_t *ops)
350 {
351         gfs_file_t *fp;
352         vnode_t *vp;
353         int error;
354
355         /*
356          * Allocate vnode and internal data structure
357          */
358         fp = kmem_zalloc(size, KM_SLEEP);
359         error = getnewvnode("zfs", vfsp, ops, &vp);
360         ASSERT(error == 0);
361         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
362         vp->v_data = (caddr_t)fp;
363
364         /*
365          * Set up various pointers
366          */
367         fp->gfs_vnode = vp;
368         fp->gfs_parent = pvp;
369         fp->gfs_size = size;
370         fp->gfs_type = GFS_FILE;
371
372         vp->v_vflag |= VV_FORCEINSMQ;
373         error = insmntque(vp, vfsp);
374         vp->v_vflag &= ~VV_FORCEINSMQ;
375         KASSERT(error == 0, ("insmntque() failed: error %d", error));
376
377         /*
378          * Initialize vnode and hold parent.
379          */
380         if (pvp)
381                 VN_HOLD(pvp);
382
383         return (vp);
384 }
385
386 /*
387  * gfs_dir_create: creates a new directory in the parent
388  *
389  *   size       - size of private data structure (v_data)
390  *   pvp        - parent vnode (GFS directory)
391  *   ops        - vnode operations vector
392  *   entries    - NULL-terminated list of static entries (if any)
393  *   maxlen     - maximum length of a directory entry
394  *   readdir_cb - readdir callback (see gfs_dir_readdir)
395  *   inode_cb   - inode callback (see gfs_dir_readdir)
396  *   lookup_cb  - lookup callback (see gfs_dir_lookup)
397  *
398  * In order to use this function, the first member of the private vnode
399  * structure (v_data) must be a gfs_dir_t.  For each directory, there are
400  * static entries, defined when the structure is initialized, and dynamic
401  * entries, retrieved through callbacks.
402  *
403  * If a directory has static entries, then it must supply a inode callback,
404  * which will compute the inode number based on the parent and the index.
405  * For a directory with dynamic entries, the caller must supply a readdir
406  * callback and a lookup callback.  If a static lookup fails, we fall back to
407  * the supplied lookup callback, if any.
408  *
409  * This function also performs the same initialization as gfs_file_create().
410  */
411 vnode_t *
412 gfs_dir_create(size_t struct_size, vnode_t *pvp, vfs_t *vfsp, vnodeops_t *ops,
413     gfs_dirent_t *entries, gfs_inode_cb inode_cb, int maxlen,
414     gfs_readdir_cb readdir_cb, gfs_lookup_cb lookup_cb)
415 {
416         vnode_t *vp;
417         gfs_dir_t *dp;
418         gfs_dirent_t *de;
419
420         vp = gfs_file_create(struct_size, pvp, vfsp, ops);
421         vp->v_type = VDIR;
422
423         dp = vp->v_data;
424         dp->gfsd_file.gfs_type = GFS_DIR;
425         dp->gfsd_maxlen = maxlen;
426
427         if (entries != NULL) {
428                 for (de = entries; de->gfse_name != NULL; de++)
429                         dp->gfsd_nstatic++;
430
431                 dp->gfsd_static = kmem_alloc(
432                     dp->gfsd_nstatic * sizeof (gfs_dirent_t), KM_SLEEP);
433                 bcopy(entries, dp->gfsd_static,
434                     dp->gfsd_nstatic * sizeof (gfs_dirent_t));
435         }
436
437         dp->gfsd_readdir = readdir_cb;
438         dp->gfsd_lookup = lookup_cb;
439         dp->gfsd_inode = inode_cb;
440
441         mutex_init(&dp->gfsd_lock, NULL, MUTEX_DEFAULT, NULL);
442
443         return (vp);
444 }
445
446 /*
447  * gfs_root_create(): create a root vnode for a GFS filesystem
448  *
449  * Similar to gfs_dir_create(), this creates a root vnode for a filesystem.  The
450  * only difference is that it takes a vfs_t instead of a vnode_t as its parent.
451  */
452 vnode_t *
453 gfs_root_create(size_t size, vfs_t *vfsp, vnodeops_t *ops, ino64_t ino,
454     gfs_dirent_t *entries, gfs_inode_cb inode_cb, int maxlen,
455     gfs_readdir_cb readdir_cb, gfs_lookup_cb lookup_cb)
456 {
457         vnode_t *vp;
458
459         VFS_HOLD(vfsp);
460         vp = gfs_dir_create(size, NULL, vfsp, ops, entries, inode_cb,
461             maxlen, readdir_cb, lookup_cb);
462         /* Manually set the inode */
463         ((gfs_file_t *)vp->v_data)->gfs_ino = ino;
464         vp->v_flag |= VROOT;
465
466         return (vp);
467 }
468
469 /*
470  * gfs_file_inactive()
471  *
472  * Called from the VOP_INACTIVE() routine.  If necessary, this routine will
473  * remove the given vnode from the parent directory and clean up any references
474  * in the VFS layer.
475  *
476  * If the vnode was not removed (due to a race with vget), then NULL is
477  * returned.  Otherwise, a pointer to the private data is returned.
478  */
479 void *
480 gfs_file_inactive(vnode_t *vp)
481 {
482         int i;
483         gfs_dirent_t *ge = NULL;
484         gfs_file_t *fp = vp->v_data;
485         gfs_dir_t *dp = NULL;
486         void *data;
487
488         if (fp->gfs_parent == NULL)
489                 goto found;
490
491         dp = fp->gfs_parent->v_data;
492
493         /*
494          * First, see if this vnode is cached in the parent.
495          */
496         gfs_dir_lock(dp);
497
498         /*
499          * Find it in the set of static entries.
500          */
501         for (i = 0; i < dp->gfsd_nstatic; i++)  {
502                 ge = &dp->gfsd_static[i];
503
504                 if (ge->gfse_vnode == vp)
505                         goto found;
506         }
507
508         /*
509          * If 'ge' is NULL, then it is a dynamic entry.
510          */
511         ge = NULL;
512
513 found:
514         VI_LOCK(vp);
515         ASSERT(vp->v_count < 2);
516         /*
517          * Really remove this vnode
518          */
519         data = vp->v_data;
520         if (ge != NULL) {
521                 /*
522                  * If this was a statically cached entry, simply set the
523                  * cached vnode to NULL.
524                  */
525                 ge->gfse_vnode = NULL;
526         }
527         if (vp->v_count == 1) {
528                 vp->v_usecount--;
529                 vdropl(vp);
530         } else {
531                 VI_UNLOCK(vp);
532         }
533
534         /*
535          * Free vnode and release parent
536          */
537         if (fp->gfs_parent) {
538                 gfs_dir_unlock(dp);
539                 VI_LOCK(fp->gfs_parent);
540                 fp->gfs_parent->v_usecount--;
541                 VI_UNLOCK(fp->gfs_parent);
542         } else {
543                 ASSERT(vp->v_vfsp != NULL);
544                 VFS_RELE(vp->v_vfsp);
545         }
546
547         return (data);
548 }
549
550 /*
551  * gfs_dir_inactive()
552  *
553  * Same as above, but for directories.
554  */
555 void *
556 gfs_dir_inactive(vnode_t *vp)
557 {
558         gfs_dir_t *dp;
559
560         ASSERT(vp->v_type == VDIR);
561
562         if ((dp = gfs_file_inactive(vp)) != NULL) {
563                 mutex_destroy(&dp->gfsd_lock);
564                 if (dp->gfsd_nstatic)
565                         kmem_free(dp->gfsd_static,
566                             dp->gfsd_nstatic * sizeof (gfs_dirent_t));
567         }
568
569         return (dp);
570 }
571
572 /*
573  * gfs_dir_lookup()
574  *
575  * Looks up the given name in the directory and returns the corresponding vnode,
576  * if found.
577  *
578  * First, we search statically defined entries, if any.  If a match is found,
579  * and GFS_CACHE_VNODE is set and the vnode exists, we simply return the
580  * existing vnode.  Otherwise, we call the static entry's callback routine,
581  * caching the result if necessary.
582  *
583  * If no static entry is found, we invoke the lookup callback, if any.  The
584  * arguments to this callback are:
585  *
586  *      int gfs_lookup_cb(vnode_t *pvp, const char *nm, vnode_t **vpp);
587  *
588  *      pvp     - parent vnode
589  *      nm      - name of entry
590  *      vpp     - pointer to resulting vnode
591  *
592  *      Returns 0 on success, non-zero on error.
593  */
594 int
595 gfs_dir_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp)
596 {
597         int i;
598         gfs_dirent_t *ge;
599         vnode_t *vp;
600         gfs_dir_t *dp = dvp->v_data;
601         int ret = 0;
602
603         ASSERT(dvp->v_type == VDIR);
604
605         if (gfs_lookup_dot(vpp, dvp, dp->gfsd_file.gfs_parent, nm) == 0)
606                 return (0);
607
608         gfs_dir_lock(dp);
609
610         /*
611          * Search static entries.
612          */
613         for (i = 0; i < dp->gfsd_nstatic; i++) {
614                 ge = &dp->gfsd_static[i];
615
616                 if (strcmp(ge->gfse_name, nm) == 0) {
617                         if (ge->gfse_vnode) {
618                                 ASSERT(ge->gfse_flags & GFS_CACHE_VNODE);
619                                 vp = ge->gfse_vnode;
620                                 VN_HOLD(vp);
621                                 goto out;
622                         }
623
624                         /*
625                          * We drop the directory lock, as the constructor will
626                          * need to do KM_SLEEP allocations.  If we return from
627                          * the constructor only to find that a parallel
628                          * operation has completed, and GFS_CACHE_VNODE is set
629                          * for this entry, we discard the result in favor of the
630                          * cached vnode.
631                          */
632                         gfs_dir_unlock(dp);
633                         vp = ge->gfse_ctor(dvp);
634                         gfs_dir_lock(dp);
635
636                         ((gfs_file_t *)vp->v_data)->gfs_index = i;
637
638                         /* Set the inode according to the callback. */
639                         ((gfs_file_t *)vp->v_data)->gfs_ino =
640                             dp->gfsd_inode(dvp, i);
641
642                         if (ge->gfse_flags & GFS_CACHE_VNODE) {
643                                 if (ge->gfse_vnode == NULL) {
644                                         ge->gfse_vnode = vp;
645                                 } else {
646                                         /*
647                                          * A parallel constructor beat us to it;
648                                          * return existing vnode.  We have to be
649                                          * careful because we can't release the
650                                          * current vnode while holding the
651                                          * directory lock; its inactive routine
652                                          * will try to lock this directory.
653                                          */
654                                         vnode_t *oldvp = vp;
655                                         vp = ge->gfse_vnode;
656                                         VN_HOLD(vp);
657
658                                         gfs_dir_unlock(dp);
659                                         VN_RELE(oldvp);
660                                         gfs_dir_lock(dp);
661                                 }
662                         }
663
664                         goto out;
665                 }
666         }
667
668         /*
669          * See if there is a dynamic constructor.
670          */
671         if (dp->gfsd_lookup) {
672                 ino64_t ino;
673                 gfs_file_t *fp;
674
675                 /*
676                  * Once again, drop the directory lock, as the lookup routine
677                  * will need to allocate memory, or otherwise deadlock on this
678                  * directory.
679                  */
680                 gfs_dir_unlock(dp);
681                 ret = dp->gfsd_lookup(dvp, nm, &vp, &ino);
682                 gfs_dir_lock(dp);
683                 if (ret != 0)
684                         goto out;
685
686                 fp = (gfs_file_t *)vp->v_data;
687                 fp->gfs_index = -1;
688                 fp->gfs_ino = ino;
689         } else {
690                 /*
691                  * No static entry found, and there is no lookup callback, so
692                  * return ENOENT.
693                  */
694                 ret = ENOENT;
695         }
696
697 out:
698         gfs_dir_unlock(dp);
699
700         if (ret == 0)
701                 *vpp = vp;
702         else
703                 *vpp = NULL;
704
705         return (ret);
706 }
707
708 /*
709  * gfs_dir_readdir: does a readdir() on the given directory
710  *
711  *    dvp       - directory vnode
712  *    uiop      - uio structure
713  *    eofp      - eof pointer
714  *    data      - arbitrary data passed to readdir callback
715  *
716  * This routine does all the readdir() dirty work.  Even so, the caller must
717  * supply two callbacks in order to get full compatibility.
718  *
719  * If the directory contains static entries, an inode callback must be
720  * specified.  This avoids having to create every vnode and call VOP_GETATTR()
721  * when reading the directory.  This function has the following arguments:
722  *
723  *      ino_t gfs_inode_cb(vnode_t *vp, int index);
724  *
725  *      vp      - vnode for the directory
726  *      index   - index in original gfs_dirent_t array
727  *
728  *      Returns the inode number for the given entry.
729  *
730  * For directories with dynamic entries, a readdir callback must be provided.
731  * This is significantly more complex, thanks to the particulars of
732  * VOP_READDIR().
733  *
734  *      int gfs_readdir_cb(vnode_t *vp, struct dirent64 *dp, int *eofp,
735  *          offset_t *off, offset_t *nextoff, void *data)
736  *
737  *      vp      - directory vnode
738  *      dp      - directory entry, sized according to maxlen given to
739  *                gfs_dir_create().  callback must fill in d_name and
740  *                d_ino.
741  *      eofp    - callback must set to 1 when EOF has been reached
742  *      off     - on entry, the last offset read from the directory.  Callback
743  *                must set to the offset of the current entry, typically left
744  *                untouched.
745  *      nextoff - callback must set to offset of next entry.  Typically
746  *                (off + 1)
747  *      data    - caller-supplied data
748  *
749  *      Return 0 on success, or error on failure.
750  */
751 int
752 gfs_dir_readdir(vnode_t *dvp, uio_t *uiop, int *eofp, int *ncookies,
753     u_long **cookies, void *data)
754 {
755         gfs_readdir_state_t gstate;
756         int error, eof = 0;
757         ino64_t ino, pino;
758         offset_t off, next;
759         gfs_dir_t *dp = dvp->v_data;
760
761         ino = dp->gfsd_file.gfs_ino;
762
763         if (dp->gfsd_file.gfs_parent == NULL)
764                 pino = ino;             /* root of filesystem */
765         else
766                 pino = ((gfs_file_t *)
767                     (dp->gfsd_file.gfs_parent->v_data))->gfs_ino;
768
769         if ((error = gfs_readdir_init(&gstate, dp->gfsd_maxlen, 1, uiop,
770             pino, ino)) != 0)
771                 return (error);
772
773         while ((error = gfs_readdir_pred(&gstate, uiop, &off, ncookies,
774             cookies)) == 0 && !eof) {
775
776                 if (off >= 0 && off < dp->gfsd_nstatic) {
777                         ino = dp->gfsd_inode(dvp, off);
778
779                         if ((error = gfs_readdir_emit(&gstate, uiop,
780                             off, ino, dp->gfsd_static[off].gfse_name, ncookies,
781                             cookies)) != 0)
782                                 break;
783
784                 } else if (dp->gfsd_readdir) {
785                         off -= dp->gfsd_nstatic;
786
787                         if ((error = dp->gfsd_readdir(dvp,
788                             gstate.grd_dirent, &eof, &off, &next,
789                             data)) != 0 || eof)
790                                 break;
791
792                         off += dp->gfsd_nstatic + 2;
793                         next += dp->gfsd_nstatic + 2;
794
795                         if ((error = gfs_readdir_emit_int(&gstate, uiop,
796                             next, ncookies, cookies)) != 0)
797                                 break;
798                 } else {
799                         /*
800                          * Offset is beyond the end of the static entries, and
801                          * we have no dynamic entries.  Set EOF.
802                          */
803                         eof = 1;
804                 }
805         }
806
807         return (gfs_readdir_fini(&gstate, error, eofp, eof));
808 }
809
810 /*
811  * gfs_vop_readdir: VOP_READDIR() entry point
812  *
813  * For use directly in vnode ops table.  Given a GFS directory, calls
814  * gfs_dir_readdir() as necessary.
815  */
816 /* ARGSUSED */
817 int
818 gfs_vop_readdir(ap)
819         struct vop_readdir_args /* {
820                 struct vnode *a_vp;
821                 struct uio *a_uio;
822                 struct ucred *a_cred;
823                 int *a_eofflag;
824                 int *ncookies;
825                 u_long **a_cookies;
826         } */ *ap;
827 {
828         vnode_t *vp = ap->a_vp;
829         uio_t *uiop = ap->a_uio;
830         int *eofp = ap->a_eofflag;
831         int ncookies = 0;
832         u_long *cookies = NULL;
833         int error;
834
835         if (ap->a_ncookies) {
836                 /*
837                  * Minimum entry size is dirent size and 1 byte for a file name.
838                  */
839                 ncookies = uiop->uio_resid / (sizeof(struct dirent) - sizeof(((struct dirent *)NULL)->d_name) + 1);
840                 cookies = malloc(ncookies * sizeof(u_long), M_TEMP, M_WAITOK);
841                 *ap->a_cookies = cookies;
842                 *ap->a_ncookies = ncookies;
843         }
844
845         error = gfs_dir_readdir(vp, uiop, eofp, &ncookies, &cookies, NULL);
846
847         if (error == 0) {
848                 /* Subtract unused cookies */
849                 if (ap->a_ncookies)
850                         *ap->a_ncookies -= ncookies;
851         } else if (ap->a_ncookies) {
852                 free(*ap->a_cookies, M_TEMP);
853                 *ap->a_cookies = NULL;
854                 *ap->a_ncookies = 0;
855         }
856
857         return (error);
858 }
859
860 /*
861  * gfs_vop_inactive: VOP_INACTIVE() entry point
862  *
863  * Given a vnode that is a GFS file or directory, call gfs_file_inactive() or
864  * gfs_dir_inactive() as necessary, and kmem_free()s associated private data.
865  */
866 /* ARGSUSED */
867 int
868 gfs_vop_inactive(ap)
869         struct vop_inactive_args /* {
870                 struct vnode *a_vp;
871                 struct thread *a_td;
872         } */ *ap;
873 {
874         vnode_t *vp = ap->a_vp;
875         gfs_file_t *fp = vp->v_data;
876         void *data;
877
878         if (fp->gfs_type == GFS_DIR)
879                 data = gfs_dir_inactive(vp);
880         else
881                 data = gfs_file_inactive(vp);
882
883         if (data != NULL)
884                 kmem_free(data, fp->gfs_size);
885         vp->v_data = NULL;
886         return (0);
887 }