kernel - Provide descriptions for lwkt.* and debug.* sysctl's
[dragonfly.git] / sys / vfs / ufs / ufs_lookup.c
1 /*
2  * Copyright (c) 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *      @(#)ufs_lookup.c        8.15 (Berkeley) 6/16/95
39  * $FreeBSD: src/sys/ufs/ufs/ufs_lookup.c,v 1.33.2.7 2001/09/22 19:22:13 iedowse Exp $
40  * $DragonFly: src/sys/vfs/ufs/ufs_lookup.c,v 1.29 2008/10/15 12:12:51 aggelos Exp $
41  */
42
43 #include "opt_ufs.h"
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/namei.h>
51 #include <sys/stat.h>
52 #include <sys/mount.h>
53 #include <sys/vnode.h>
54 #include <sys/sysctl.h>
55
56 #include <vm/vm.h>
57 #include <vm/vm_extern.h>
58
59 #include "quota.h"
60 #include "inode.h"
61 #include "dir.h"
62 #ifdef UFS_DIRHASH
63 #include "dirhash.h"
64 #endif
65 #include "ufsmount.h"
66 #include "ufs_extern.h"
67 #include "ffs_extern.h"
68
69 #ifdef DIAGNOSTIC
70 int     dirchk = 1;
71 #else
72 int     dirchk = 0;
73 #endif
74
75 SYSCTL_INT(_debug, OID_AUTO, dircheck, CTLFLAG_RW, &dirchk, 0,
76     "Enable full validation checks of directory");
77
78 /* true if old FS format...*/
79 #define OFSFMT(vp)      ((vp)->v_mount->mnt_maxsymlinklen <= 0)
80
81 /*
82  * Convert a component of a pathname into a pointer to a locked inode.
83  * This is a very central and rather complicated routine.
84  * If the filesystem is not maintained in a strict tree hierarchy,
85  * this can result in a deadlock situation (see comments in code below).
86  *
87  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
88  * on whether the name is to be looked up, created, renamed, or deleted.
89  * When CREATE, RENAME, or DELETE is specified, information usable in
90  * creating, renaming, or deleting a directory entry may be calculated.
91  * If flag has LOCKPARENT or'ed into it and the target of the pathname
92  * exists, lookup returns both the target and its parent directory locked.
93  * When creating or renaming and LOCKPARENT is specified, the target may
94  * not be ".".  When deleting and LOCKPARENT is specified, the target may
95  * be "."., but the caller must check to ensure it does an vrele and vput
96  * instead of two vputs.
97  *
98  * Overall outline of ufs_lookup:
99  *
100  *      search for name in directory, to found or notfound
101  * notfound:
102  *      if creating, return locked directory, leaving info on available slots
103  *      else return error
104  * found:
105  *      if at end of path and deleting, return information to allow delete
106  *      if at end of path and rewriting (RENAME and LOCKPARENT), lock target
107  *        inode and return info to allow rewrite
108  *      if not at end, add name to cache; if at end and neither creating
109  *        nor deleting, add name to cache
110  *
111  * ufs_lookup(struct vnode *a_dvp, struct vnode **a_vpp,
112  *            struct componentname *a_cnp)
113  */
114 int
115 ufs_lookup(struct vop_old_lookup_args *ap)
116 {
117         struct vnode *vdp;      /* vnode for directory being searched */
118         struct inode *dp;       /* inode for directory being searched */
119         struct buf *bp;                 /* a buffer of directory entries */
120         struct direct *ep;              /* the current directory entry */
121         int entryoffsetinblock;         /* offset of ep in bp's buffer */
122         enum {NONE, COMPACT, FOUND} slotstatus;
123         doff_t slotoffset;              /* offset of area with free space */
124         int slotsize;                   /* size of area at slotoffset */
125         int slotfreespace;              /* amount of space free in slot */
126         int slotneeded;                 /* size of the entry we're seeking */
127         int numdirpasses;               /* strategy for directory search */
128         doff_t endsearch;               /* offset to end directory search */
129         doff_t prevoff;                 /* prev entry dp->i_offset */
130         struct vnode *pdp;              /* saved dp during symlink work */
131         struct vnode *tdp;              /* returned by VFS_VGET */
132         doff_t enduseful;               /* pointer past last used dir slot */
133         u_long bmask;                   /* block offset mask */
134         int lockparent;                 /* 1 => lockparent flag is set */
135         int wantparent;                 /* 1 => wantparent or lockparent flag */
136         int namlen, error;
137         struct vnode **vpp = ap->a_vpp;
138         struct componentname *cnp = ap->a_cnp;
139         struct ucred *cred = cnp->cn_cred;
140         int flags = cnp->cn_flags;
141         int nameiop = cnp->cn_nameiop;
142
143         bp = NULL;
144         slotoffset = -1;
145         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
146 /*
147  *  XXX there was a soft-update diff about this I couldn't merge.
148  * I think this was the equiv.
149  */
150         *vpp = NULL;
151
152         vdp = ap->a_dvp;
153         dp = VTOI(vdp);
154         lockparent = flags & CNP_LOCKPARENT;
155         wantparent = flags & (CNP_LOCKPARENT|CNP_WANTPARENT);
156
157         /*
158          * We now have a segment name to search for, and a directory to search.
159          *
160          * Suppress search for slots unless creating
161          * file and at end of pathname, in which case
162          * we watch for a place to put the new file in
163          * case it doesn't already exist.
164          */
165         slotstatus = FOUND;
166         slotfreespace = slotsize = slotneeded = 0;
167         if (nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME) {
168                 slotstatus = NONE;
169                 slotneeded = DIRECTSIZ(cnp->cn_namelen);
170         }
171         bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
172
173 #ifdef UFS_DIRHASH
174         /*
175          * Use dirhash for fast operations on large directories. The logic
176          * to determine whether to hash the directory is contained within
177          * ufsdirhash_build(); a zero return means that it decided to hash
178          * this directory and it successfully built up the hash table.
179          */
180         if (ufsdirhash_build(dp) == 0) {
181                 /* Look for a free slot if needed. */
182                 enduseful = dp->i_size;
183                 if (slotstatus != FOUND) {
184                         slotoffset = ufsdirhash_findfree(dp, slotneeded,
185                             &slotsize);
186                         if (slotoffset >= 0) {
187                                 slotstatus = COMPACT;
188                                 enduseful = ufsdirhash_enduseful(dp);
189                                 if (enduseful < 0)
190                                         enduseful = dp->i_size;
191                         }
192                 }
193                 /* Look up the component. */
194                 numdirpasses = 1;
195                 entryoffsetinblock = 0; /* silence compiler warning */
196                 switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen,
197                     &dp->i_offset, &bp, nameiop == NAMEI_DELETE ? &prevoff : NULL)) {
198                 case 0:
199                         ep = (struct direct *)((char *)bp->b_data +
200                             (dp->i_offset & bmask));
201                         goto foundentry;
202                 case ENOENT:
203                         dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ);
204                         goto notfound;
205                 default:
206                         /* Something failed; just do a linear search. */
207                         break;
208                 }
209         }
210 #endif /* UFS_DIRHASH */
211         /*
212          * If there is cached information on a previous search of
213          * this directory, pick up where we last left off.
214          * We cache only lookups as these are the most common
215          * and have the greatest payoff. Caching CREATE has little
216          * benefit as it usually must search the entire directory
217          * to determine that the entry does not exist. Caching the
218          * location of the last DELETE or RENAME has not reduced
219          * profiling time and hence has been removed in the interest
220          * of simplicity.
221          */
222         if (nameiop != NAMEI_LOOKUP || dp->i_diroff == 0 ||
223             dp->i_diroff >= dp->i_size) {
224                 entryoffsetinblock = 0;
225                 dp->i_offset = 0;
226                 numdirpasses = 1;
227         } else {
228                 dp->i_offset = dp->i_diroff;
229                 if ((entryoffsetinblock = dp->i_offset & bmask) &&
230                     (error = ffs_blkatoff(vdp, (off_t)dp->i_offset, NULL, &bp)))
231                         return (error);
232                 numdirpasses = 2;
233         }
234         prevoff = dp->i_offset;
235         endsearch = roundup2(dp->i_size, DIRBLKSIZ);
236         enduseful = 0;
237
238 searchloop:
239         while (dp->i_offset < endsearch) {
240                 /*
241                  * If necessary, get the next directory block.
242                  */
243                 if ((dp->i_offset & bmask) == 0) {
244                         if (bp != NULL)
245                                 brelse(bp);
246                         error =
247                             ffs_blkatoff(vdp, (off_t)dp->i_offset, NULL, &bp);
248                         if (error)
249                                 return (error);
250                         entryoffsetinblock = 0;
251                 }
252                 /*
253                  * If still looking for a slot, and at a DIRBLKSIZE
254                  * boundary, have to start looking for free space again.
255                  */
256                 if (slotstatus == NONE &&
257                     (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
258                         slotoffset = -1;
259                         slotfreespace = 0;
260                 }
261                 /*
262                  * Get pointer to next entry.
263                  * Full validation checks are slow, so we only check
264                  * enough to insure forward progress through the
265                  * directory. Complete checks can be run by patching
266                  * "dirchk" to be true.
267                  */
268                 ep = (struct direct *)((char *)bp->b_data + entryoffsetinblock);
269                 if (ep->d_reclen == 0 || ep->d_reclen >
270                     DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
271                     (dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock))) {
272                         int i;
273
274                         ufs_dirbad(dp, dp->i_offset, "mangled entry");
275                         i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
276                         dp->i_offset += i;
277                         entryoffsetinblock += i;
278                         continue;
279                 }
280
281                 /*
282                  * If an appropriate sized slot has not yet been found,
283                  * check to see if one is available. Also accumulate space
284                  * in the current block so that we can determine if
285                  * compaction is viable.
286                  */
287                 if (slotstatus != FOUND) {
288                         int size = ep->d_reclen;
289
290                         if (ep->d_ino != 0)
291                                 size -= DIRSIZ(OFSFMT(vdp), ep);
292                         if (size > 0) {
293                                 if (size >= slotneeded) {
294                                         slotstatus = FOUND;
295                                         slotoffset = dp->i_offset;
296                                         slotsize = ep->d_reclen;
297                                 } else if (slotstatus == NONE) {
298                                         slotfreespace += size;
299                                         if (slotoffset == -1)
300                                                 slotoffset = dp->i_offset;
301                                         if (slotfreespace >= slotneeded) {
302                                                 slotstatus = COMPACT;
303                                                 slotsize = dp->i_offset +
304                                                       ep->d_reclen - slotoffset;
305                                         }
306                                 }
307                         }
308                 }
309
310                 /*
311                  * Check for a name match.
312                  */
313                 if (ep->d_ino) {
314 #                       if (BYTE_ORDER == LITTLE_ENDIAN)
315                                 if (OFSFMT(vdp))
316                                         namlen = ep->d_type;
317                                 else
318                                         namlen = ep->d_namlen;
319 #                       else
320                                 namlen = ep->d_namlen;
321 #                       endif
322                         if (namlen == cnp->cn_namelen &&
323                                 (cnp->cn_nameptr[0] == ep->d_name[0]) &&
324                             !bcmp(cnp->cn_nameptr, ep->d_name,
325                                 (unsigned)namlen)) {
326 #ifdef UFS_DIRHASH
327 foundentry:
328 #endif
329                                 /*
330                                  * Save directory entry's inode number and
331                                  * reclen in ndp->ni_ufs area, and release
332                                  * directory buffer.
333                                  */
334                                 if (vdp->v_mount->mnt_maxsymlinklen > 0 &&
335                                     ep->d_type == DT_WHT) {
336                                         slotstatus = FOUND;
337                                         slotoffset = dp->i_offset;
338                                         slotsize = ep->d_reclen;
339                                         dp->i_reclen = slotsize;
340                                         enduseful = dp->i_size;
341                                         ap->a_cnp->cn_flags |= CNP_ISWHITEOUT;
342                                         numdirpasses--;
343                                         goto notfound;
344                                 }
345                                 dp->i_ino = ep->d_ino;
346                                 dp->i_reclen = ep->d_reclen;
347                                 goto found;
348                         }
349                 }
350                 prevoff = dp->i_offset;
351                 dp->i_offset += ep->d_reclen;
352                 entryoffsetinblock += ep->d_reclen;
353                 if (ep->d_ino)
354                         enduseful = dp->i_offset;
355         }
356 notfound:
357         /*
358          * If we started in the middle of the directory and failed
359          * to find our target, we must check the beginning as well.
360          */
361         if (numdirpasses == 2) {
362                 numdirpasses--;
363                 dp->i_offset = 0;
364                 endsearch = dp->i_diroff;
365                 goto searchloop;
366         }
367         if (bp != NULL)
368                 brelse(bp);
369         /*
370          * If creating, and at end of pathname and current
371          * directory has not been removed, then can consider
372          * allowing file to be created.
373          */
374         if ((nameiop == NAMEI_CREATE || nameiop == NAMEI_RENAME ||
375              (nameiop == NAMEI_DELETE &&
376               (ap->a_cnp->cn_flags & CNP_DOWHITEOUT) &&
377               (ap->a_cnp->cn_flags & CNP_ISWHITEOUT))) &&
378             dp->i_effnlink != 0) {
379                 /*
380                  * Access for write is interpreted as allowing
381                  * creation of files in the directory.
382                  */
383                 error = VOP_EACCESS(vdp, VWRITE, cred);
384                 if (error)
385                         return (error);
386                 /*
387                  * Return an indication of where the new directory
388                  * entry should be put.  If we didn't find a slot,
389                  * then set dp->i_count to 0 indicating
390                  * that the new slot belongs at the end of the
391                  * directory. If we found a slot, then the new entry
392                  * can be put in the range from dp->i_offset to
393                  * dp->i_offset + dp->i_count.
394                  */
395                 if (slotstatus == NONE) {
396                         dp->i_offset = roundup2(dp->i_size, DIRBLKSIZ);
397                         dp->i_count = 0;
398                         enduseful = dp->i_offset;
399                 } else if (nameiop == NAMEI_DELETE) {
400                         dp->i_offset = slotoffset;
401                         if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
402                                 dp->i_count = 0;
403                         else
404                                 dp->i_count = dp->i_offset - prevoff;
405                 } else {
406                         dp->i_offset = slotoffset;
407                         dp->i_count = slotsize;
408                         if (enduseful < slotoffset + slotsize)
409                                 enduseful = slotoffset + slotsize;
410                 }
411                 dp->i_endoff = roundup2(enduseful, DIRBLKSIZ);
412                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
413                 /*
414                  * We return with the directory locked, so that
415                  * the parameters we set up above will still be
416                  * valid if we actually decide to do a direnter().
417                  * We return ni_vp == NULL to indicate that the entry
418                  * does not currently exist; we leave a pointer to
419                  * the (locked) directory inode in ndp->ni_dvp.
420                  * The pathname buffer is saved so that the name
421                  * can be obtained later.
422                  *
423                  * NB - if the directory is unlocked, then this
424                  * information cannot be used.
425                  */
426                 if (!lockparent) {
427                         vn_unlock(vdp);
428                         cnp->cn_flags |= CNP_PDIRUNLOCK;
429                 }
430                 return (EJUSTRETURN);
431         }
432         return (ENOENT);
433
434 found:
435         /*
436          * Check that directory length properly reflects presence
437          * of this entry.
438          */
439         if (dp->i_offset + DIRSIZ(OFSFMT(vdp), ep) > dp->i_size) {
440                 ufs_dirbad(dp, dp->i_offset, "i_size too small");
441                 dp->i_size = dp->i_offset + DIRSIZ(OFSFMT(vdp), ep);
442                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
443         }
444         brelse(bp);
445
446         /*
447          * Found component in pathname.
448          * If the final component of path name, save information
449          * in the cache as to where the entry was found.
450          */
451         if (nameiop == NAMEI_LOOKUP)
452                 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1);
453
454         /*
455          * If deleting, and at end of pathname, return
456          * parameters which can be used to remove file.
457          * If the wantparent flag isn't set, we return only
458          * the directory (in ndp->ni_dvp), otherwise we go
459          * on and lock the inode, being careful with ".".
460          */
461         if (nameiop == NAMEI_DELETE) {
462                 /*
463                  * Write access to directory required to delete files.
464                  */
465                 error = VOP_EACCESS(vdp, VWRITE, cred);
466                 if (error)
467                         return (error);
468                 /*
469                  * Return pointer to current entry in dp->i_offset,
470                  * and distance past previous entry (if there
471                  * is a previous entry in this block) in dp->i_count.
472                  * Save directory inode pointer in ndp->ni_dvp for dirremove().
473                  */
474                 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0)
475                         dp->i_count = 0;
476                 else
477                         dp->i_count = dp->i_offset - prevoff;
478                 if (dp->i_number == dp->i_ino) {
479                         vref(vdp);
480                         *vpp = vdp;
481                         return (0);
482                 }
483                 if (flags & CNP_ISDOTDOT)
484                         vn_unlock(vdp); /* race to get the inode */
485                 error = VFS_VGET(vdp->v_mount, NULL, dp->i_ino, &tdp);
486                 if (flags & CNP_ISDOTDOT) {
487                         if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY) != 0)
488                                 cnp->cn_flags |= CNP_PDIRUNLOCK;
489                 }
490                 if (error)
491                         return (error);
492                 /*
493                  * If directory is "sticky", then user must own
494                  * the directory, or the file in it, else she
495                  * may not delete it (unless she's root). This
496                  * implements append-only directories.
497                  */
498                 if ((dp->i_mode & ISVTX) &&
499                     cred->cr_uid != 0 &&
500                     cred->cr_uid != dp->i_uid &&
501                     VTOI(tdp)->i_uid != cred->cr_uid) {
502                         vput(tdp);
503                         return (EPERM);
504                 }
505                 *vpp = tdp;
506                 if (!lockparent) {
507                         vn_unlock(vdp);
508                         cnp->cn_flags |= CNP_PDIRUNLOCK;
509                 }
510                 return (0);
511         }
512
513         /*
514          * If rewriting (RENAME), return the inode and the
515          * information required to rewrite the present directory
516          * Must get inode of directory entry to verify it's a
517          * regular file, or empty directory.
518          */
519         if (nameiop == NAMEI_RENAME && wantparent) {
520                 if ((error = VOP_EACCESS(vdp, VWRITE, cred)) != 0)
521                         return (error);
522                 /*
523                  * Careful about locking second inode.
524                  * This can only occur if the target is ".".
525                  */
526                 if (dp->i_number == dp->i_ino)
527                         return (EISDIR);
528                 if (flags & CNP_ISDOTDOT)
529                         vn_unlock(vdp); /* race to get the inode */
530                 error = VFS_VGET(vdp->v_mount, NULL, dp->i_ino, &tdp);
531                 if (flags & CNP_ISDOTDOT) {
532                         if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY) != 0)
533                                 cnp->cn_flags |= CNP_PDIRUNLOCK;
534                 }
535                 if (error)
536                         return (error);
537                 *vpp = tdp;
538                 if (!lockparent) {
539                         vn_unlock(vdp);
540                         cnp->cn_flags |= CNP_PDIRUNLOCK;
541                 }
542                 return (0);
543         }
544
545         /*
546          * Step through the translation in the name.  We do not `vput' the
547          * directory because we may need it again if a symbolic link
548          * is relative to the current directory.  Instead we save it
549          * unlocked as "pdp".  We must get the target inode before unlocking
550          * the directory to insure that the inode will not be removed
551          * before we get it.  We prevent deadlock by always fetching
552          * inodes from the root, moving down the directory tree. Thus
553          * when following backward pointers ".." we must unlock the
554          * parent directory before getting the requested directory.
555          * There is a potential race condition here if both the current
556          * and parent directories are removed before the VFS_VGET for the
557          * inode associated with ".." returns.  We hope that this occurs
558          * infrequently since we cannot avoid this race condition without
559          * implementing a sophisticated deadlock detection algorithm.
560          * Note also that this simple deadlock detection scheme will not
561          * work if the filesystem has any hard links other than ".."
562          * that point backwards in the directory structure.
563          */
564         pdp = vdp;
565         if (flags & CNP_ISDOTDOT) {
566                 vn_unlock(pdp); /* race to get the inode */
567                 cnp->cn_flags |= CNP_PDIRUNLOCK;
568                 error = VFS_VGET(vdp->v_mount, NULL, dp->i_ino, &tdp);
569                 if (error) {
570                         if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY) == 0)
571                                 cnp->cn_flags &= ~CNP_PDIRUNLOCK;
572                         return (error);
573                 }
574                 if (lockparent) {
575                         if ((error = vn_lock(pdp, LK_EXCLUSIVE)) != 0) {
576                                 vput(tdp);
577                                 return (error);
578                         }
579                         cnp->cn_flags &= ~CNP_PDIRUNLOCK;
580                 }
581                 *vpp = tdp;
582         } else if (dp->i_number == dp->i_ino) {
583                 vref(vdp);      /* we want ourself, ie "." */
584                 *vpp = vdp;
585         } else {
586                 error = VFS_VGET(vdp->v_mount, NULL, dp->i_ino, &tdp);
587                 if (error)
588                         return (error);
589                 if (!lockparent) {
590                         vn_unlock(pdp);
591                         cnp->cn_flags |= CNP_PDIRUNLOCK;
592                 }
593                 *vpp = tdp;
594         }
595         return (0);
596 }
597
598 void
599 ufs_dirbad(struct inode *ip, doff_t offset, char *how)
600 {
601         struct mount *mp;
602
603         mp = ITOV(ip)->v_mount;
604         (void)kprintf("%s: bad dir ino %lu at offset %ld: %s\n",
605             mp->mnt_stat.f_mntfromname, (u_long)ip->i_number, (long)offset, how);
606         if ((mp->mnt_flag & MNT_RDONLY) == 0)
607                 panic("ufs_dirbad: bad dir");
608 }
609
610 /*
611  * Do consistency checking on a directory entry:
612  *      record length must be multiple of 4
613  *      entry must fit in rest of its DIRBLKSIZ block
614  *      record must be large enough to contain entry
615  *      name is not longer than MAXNAMLEN
616  *      name must be as long as advertised, and null terminated
617  */
618 int
619 ufs_dirbadentry(struct vnode *dp, struct direct *ep, int entryoffsetinblock)
620 {
621         int i;
622         int namlen;
623
624 #       if (BYTE_ORDER == LITTLE_ENDIAN)
625                 if (OFSFMT(dp))
626                         namlen = ep->d_type;
627                 else
628                         namlen = ep->d_namlen;
629 #       else
630                 namlen = ep->d_namlen;
631 #       endif
632         if ((ep->d_reclen & 0x3) != 0 ||
633             ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
634             ep->d_reclen < DIRSIZ(OFSFMT(dp), ep) || namlen > MAXNAMLEN) {
635                 /*return (1); */
636                 kprintf("First bad\n");
637                 goto bad;
638         }
639         if (ep->d_ino == 0)
640                 return (0);
641         for (i = 0; i < namlen; i++)
642                 if (ep->d_name[i] == '\0') {
643                         /*return (1); */
644                         kprintf("Second bad\n");
645                         goto bad;
646         }
647         if (ep->d_name[i])
648                 goto bad;
649         return (0);
650 bad:
651         return (1);
652 }
653
654 /*
655  * Construct a new directory entry after a call to namei, using the
656  * parameters that it left in the componentname argument cnp. The
657  * argument ip is the inode to which the new directory entry will refer.
658  */
659 void
660 ufs_makedirentry(struct inode *ip, struct componentname *cnp,
661                  struct direct *newdirp)
662 {
663
664         newdirp->d_ino = ip->i_number;
665         newdirp->d_namlen = cnp->cn_namelen;
666         bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1);
667         if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0)
668                 newdirp->d_type = IFTODT(ip->i_mode);
669         else {
670                 newdirp->d_type = 0;
671 #               if (BYTE_ORDER == LITTLE_ENDIAN)
672                         { u_char tmp = newdirp->d_namlen;
673                         newdirp->d_namlen = newdirp->d_type;
674                         newdirp->d_type = tmp; }
675 #               endif
676         }
677 }
678
679 /*
680  * Write a directory entry after a call to namei, using the parameters
681  * that it left in the directory inode. The argument dirp is the new directory
682  * entry contents. Dvp is a pointer to the directory to be written,
683  * which was left locked by namei. Remaining parameters (dp->i_offset, 
684  * dp->i_count) indicate how the space for the new entry is to be obtained.
685  * Non-null bp indicates that a directory is being created (for the
686  * soft dependency code).
687  */
688 int
689 ufs_direnter(struct vnode *dvp, struct vnode *tvp, struct direct *dirp,
690              struct componentname *cnp, struct buf *newdirbp)
691 {
692         struct ucred *cred;
693         int newentrysize;
694         struct inode *dp;
695         struct buf *bp;
696         uint dsize;
697         struct direct *ep, *nep;
698         int error, ret, blkoff, loc, spacefree, flags;
699         char *dirbuf;
700
701         cred = cnp->cn_cred;
702         KKASSERT(cred != NULL);
703
704         dp = VTOI(dvp);
705         newentrysize = DIRSIZ(OFSFMT(dvp), dirp);
706
707         if (dp->i_count == 0) {
708                 /*
709                  * If dp->i_count is 0, then namei could find no
710                  * space in the directory. Here, dp->i_offset will
711                  * be on a directory block boundary and we will write the
712                  * new entry into a fresh block.
713                  */
714                 if (dp->i_offset & (DIRBLKSIZ - 1))
715                         panic("ufs_direnter: newblk");
716                 nvnode_pager_setsize(dvp, dp->i_offset + DIRBLKSIZ,
717                                      DIRBLKSIZ, -1);
718                 flags = B_CLRBUF;
719                 if (!DOINGSOFTDEP(dvp) && !DOINGASYNC(dvp))
720                         flags |= B_SYNC;
721                 if ((error = VOP_BALLOC(dvp, (off_t)dp->i_offset, DIRBLKSIZ,
722                     cred, flags, &bp)) != 0) {
723                         if (DOINGSOFTDEP(dvp) && newdirbp != NULL)
724                                 bdwrite(newdirbp);
725                         return (error);
726                 }
727                 dp->i_size = dp->i_offset + DIRBLKSIZ;
728                 dp->i_flag |= IN_CHANGE | IN_UPDATE;
729                 dirp->d_reclen = DIRBLKSIZ;
730                 blkoff = dp->i_offset &
731                     (VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_iosize - 1);
732                 bcopy((caddr_t)dirp, (caddr_t)bp->b_data + blkoff,newentrysize);
733 #ifdef UFS_DIRHASH
734                 if (dp->i_dirhash != NULL) {
735                         ufsdirhash_newblk(dp, dp->i_offset);
736                         ufsdirhash_add(dp, dirp, dp->i_offset);
737                         ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff,
738                             dp->i_offset);
739                 }
740 #endif
741                 if (DOINGSOFTDEP(dvp)) {
742                         /*
743                          * Ensure that the entire newly allocated block is a
744                          * valid directory so that future growth within the
745                          * block does not have to ensure that the block is
746                          * written before the inode.
747                          */
748                         blkoff += DIRBLKSIZ;
749                         while (blkoff < bp->b_bcount) {
750                                 ((struct direct *)
751                                    (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
752                                 blkoff += DIRBLKSIZ;
753                         }
754                         softdep_setup_directory_add(bp, dp, dp->i_offset,
755                             dirp->d_ino, newdirbp);
756                         bdwrite(bp);
757                         return (ffs_update(dvp, 0));
758                 }
759                 if (DOINGASYNC(dvp)) {
760                         bdwrite(bp);
761                         return (ffs_update(dvp, 0));
762                 }
763                 error = bwrite(bp);
764                 ret = ffs_update(dvp, 1);
765                 if (error == 0)
766                         return (ret);
767                 return (error);
768         }
769
770         /*
771          * If dp->i_count is non-zero, then namei found space for the new
772          * entry in the range dp->i_offset to dp->i_offset + dp->i_count
773          * in the directory. To use this space, we may have to compact
774          * the entries located there, by copying them together towards the
775          * beginning of the block, leaving the free space in one usable
776          * chunk at the end.
777          */
778
779         /*
780          * Increase size of directory if entry eats into new space.
781          * This should never push the size past a new multiple of
782          * DIRBLKSIZE.
783          *
784          * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
785          */
786         if (dp->i_offset + dp->i_count > dp->i_size)
787                 dp->i_size = dp->i_offset + dp->i_count;
788         /*
789          * Get the block containing the space for the new directory entry.
790          */
791         error = ffs_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, &bp);
792         if (error) {
793                 if (DOINGSOFTDEP(dvp) && newdirbp != NULL)
794                         bdwrite(newdirbp);
795                 return (error);
796         }
797         /*
798          * Find space for the new entry. In the simple case, the entry at
799          * offset base will have the space. If it does not, then namei
800          * arranged that compacting the region dp->i_offset to
801          * dp->i_offset + dp->i_count would yield the space.
802          */
803         ep = (struct direct *)dirbuf;
804         dsize = ep->d_ino ? DIRSIZ(OFSFMT(dvp), ep) : 0;
805         spacefree = ep->d_reclen - dsize;
806         for (loc = ep->d_reclen; loc < dp->i_count; ) {
807                 nep = (struct direct *)(dirbuf + loc);
808
809                 /* Trim the existing slot (NB: dsize may be zero). */
810                 ep->d_reclen = dsize;
811                 ep = (struct direct *)((char *)ep + dsize);
812
813                 /* Read nep->d_reclen now as the bcopy() may clobber it. */
814                 loc += nep->d_reclen;
815                 if (nep->d_ino == 0) {
816                         /*
817                          * A mid-block unused entry. Such entries are
818                          * never created by the kernel, but fsck_ffs
819                          * can create them (and it doesn't fix them).
820                          *
821                          * Add up the free space, and initialise the
822                          * relocated entry since we don't bcopy it.
823                          */
824                         spacefree += nep->d_reclen;
825                         ep->d_ino = 0;
826                         dsize = 0;
827                         continue;
828                 }
829                 dsize = DIRSIZ(OFSFMT(dvp), nep);
830                 spacefree += nep->d_reclen - dsize;
831 #ifdef UFS_DIRHASH
832                 if (dp->i_dirhash != NULL)
833                         ufsdirhash_move(dp, nep,
834                             dp->i_offset + ((char *)nep - dirbuf),
835                             dp->i_offset + ((char *)ep - dirbuf));
836 #endif
837                 if (DOINGSOFTDEP(dvp))
838                         softdep_change_directoryentry_offset(dp, dirbuf,
839                             (caddr_t)nep, (caddr_t)ep, dsize); 
840                 else
841                         bcopy((caddr_t)nep, (caddr_t)ep, dsize);
842         }
843         /*
844          * Here, `ep' points to a directory entry containing `dsize' in-use
845          * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0,
846          * then the entry is completely unused (dsize == 0). The value
847          * of ep->d_reclen is always indeterminate.
848          *
849          * Update the pointer fields in the previous entry (if any),
850          * copy in the new entry, and write out the block.
851          */
852         if (ep->d_ino == 0 ||
853             (ep->d_ino == WINO &&
854              bcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) {
855                 if (spacefree + dsize < newentrysize)
856                         panic("ufs_direnter: compact1");
857                 dirp->d_reclen = spacefree + dsize;
858         } else {
859                 if (spacefree < newentrysize)
860                         panic("ufs_direnter: compact2");
861                 dirp->d_reclen = spacefree;
862                 ep->d_reclen = dsize;
863                 ep = (struct direct *)((char *)ep + dsize);
864         }
865 #ifdef UFS_DIRHASH
866         if (dp->i_dirhash != NULL && (ep->d_ino == 0 ||
867             dirp->d_reclen == spacefree))
868                 ufsdirhash_add(dp, dirp, dp->i_offset + ((char *)ep - dirbuf));
869 #endif
870         bcopy((caddr_t)dirp, (caddr_t)ep, (uint)newentrysize);
871 #ifdef UFS_DIRHASH
872         if (dp->i_dirhash != NULL)
873                 ufsdirhash_checkblock(dp, dirbuf -
874                     (dp->i_offset & (DIRBLKSIZ - 1)),
875                     dp->i_offset & ~(DIRBLKSIZ - 1));
876 #endif
877
878         if (DOINGSOFTDEP(dvp)) {
879                 softdep_setup_directory_add(bp, dp,
880                     dp->i_offset + (caddr_t)ep - dirbuf, dirp->d_ino, newdirbp);
881                 bdwrite(bp);
882         } else {
883                 if (DOINGASYNC(dvp)) {
884                         bdwrite(bp);
885                         error = 0;
886                 } else {
887                         error = bowrite(bp);
888                 }
889         }
890         dp->i_flag |= IN_CHANGE | IN_UPDATE;
891         /*
892          * If all went well, and the directory can be shortened, proceed
893          * with the truncation. Note that we have to unlock the inode for
894          * the entry that we just entered, as the truncation may need to
895          * lock other inodes which can lead to deadlock if we also hold a
896          * lock on the newly entered node.
897          */
898         if (error == 0 && dp->i_endoff && dp->i_endoff < dp->i_size) {
899                 if (tvp != NULL)
900                         vn_unlock(tvp);
901 #ifdef UFS_DIRHASH
902                 if (dp->i_dirhash != NULL)
903                         ufsdirhash_dirtrunc(dp, dp->i_endoff);
904 #endif
905                 (void)ffs_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC, cred);
906                 if (tvp != NULL)
907                         vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
908         }
909         return (error);
910 }
911
912 /*
913  * Remove a directory entry after a call to namei, using
914  * the parameters which it left in the directory inode. The entry
915  * dp->i_offset contains the offset into the directory of the
916  * entry to be eliminated.  The dp->i_count field contains the
917  * size of the previous record in the directory.  If this
918  * is 0, the first entry is being deleted, so we need only
919  * zero the inode number to mark the entry as free.  If the
920  * entry is not the first in the directory, we must reclaim
921  * the space of the now empty record by adding the record size
922  * to the size of the previous entry.
923  */
924 int
925 ufs_dirremove(struct vnode *dvp, struct inode *ip, int flags, int isrmdir)
926 {
927         struct inode *dp;
928         struct direct *ep;
929         struct buf *bp;
930         int error;
931
932         dp = VTOI(dvp);
933
934         if (flags & CNP_DOWHITEOUT) {
935                 /*
936                  * Whiteout entry: set d_ino to WINO.
937                  */
938                 if ((error =
939                     ffs_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0)
940                         return (error);
941                 ep->d_ino = WINO;
942                 ep->d_type = DT_WHT;
943                 goto out;
944         }
945
946         if ((error = ffs_blkatoff(dvp,
947             (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0)
948                 return (error);
949 #ifdef UFS_DIRHASH
950         /*
951          * Remove the dirhash entry. This is complicated by the fact
952          * that `ep' is the previous entry when dp->i_count != 0.
953          */
954         if (dp->i_dirhash != NULL)
955                 ufsdirhash_remove(dp, (dp->i_count == 0) ? ep :
956                    (struct direct *)((char *)ep + ep->d_reclen), dp->i_offset);
957 #endif
958         if (dp->i_count == 0) {
959                 /*
960                  * First entry in block: set d_ino to zero.
961                  */
962                 ep->d_ino = 0;
963         } else {
964                 /*
965                  * Collapse new free space into previous entry.
966                  */
967                 ep->d_reclen += dp->i_reclen;
968         }
969 #ifdef UFS_DIRHASH
970         if (dp->i_dirhash != NULL)
971                 ufsdirhash_checkblock(dp, (char *)ep -
972                     ((dp->i_offset - dp->i_count) & (DIRBLKSIZ - 1)),
973                     dp->i_offset & ~(DIRBLKSIZ - 1));
974 #endif
975 out:
976         if (DOINGSOFTDEP(dvp)) {
977                 if (ip) {
978                         ip->i_effnlink--;
979                         softdep_change_linkcnt(ip);
980                         softdep_setup_remove(bp, dp, ip, isrmdir);
981                 }
982                 if (softdep_slowdown(dvp)) {
983                         error = bwrite(bp);
984                 } else {
985                         bdwrite(bp);
986                         error = 0;
987                 }
988         } else {
989                 if (ip) {
990                         ip->i_effnlink--;
991                         ip->i_nlink--;
992                         ip->i_flag |= IN_CHANGE;
993                 }
994                 if (flags & CNP_DOWHITEOUT)
995                         error = bwrite(bp);
996                 else if (DOINGASYNC(dvp) && dp->i_count != 0) {
997                         bdwrite(bp);
998                         error = 0;
999                 } else
1000                         error = bowrite(bp);
1001         }
1002         dp->i_flag |= IN_CHANGE | IN_UPDATE;
1003         return (error);
1004 }
1005
1006 /*
1007  * Rewrite an existing directory entry to point at the inode
1008  * supplied.  The parameters describing the directory entry are
1009  * set up by a call to namei.
1010  */
1011 int
1012 ufs_dirrewrite(struct inode *dp, struct inode *oip, ino_t newinum, int newtype,
1013                int isrmdir)
1014 {
1015         struct buf *bp;
1016         struct direct *ep;
1017         struct vnode *vdp = ITOV(dp);
1018         int error;
1019
1020         error = ffs_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
1021         if (error)
1022                 return (error);
1023         ep->d_ino = newinum;
1024         if (!OFSFMT(vdp))
1025                 ep->d_type = newtype;
1026         oip->i_effnlink--;
1027         if (DOINGSOFTDEP(vdp)) {
1028                 softdep_change_linkcnt(oip);
1029                 softdep_setup_directory_change(bp, dp, oip, newinum, isrmdir);
1030                 bdwrite(bp);
1031         } else {
1032                 oip->i_nlink--;
1033                 oip->i_flag |= IN_CHANGE;
1034                 if (DOINGASYNC(vdp)) {
1035                         bdwrite(bp);
1036                         error = 0;
1037                 } else {
1038                         error = bowrite(bp);
1039                 }
1040         }
1041         dp->i_flag |= IN_CHANGE | IN_UPDATE;
1042         return (error);
1043 }
1044
1045 /*
1046  * Check if a directory is empty or not.
1047  * Inode supplied must be locked.
1048  *
1049  * Using a struct dirtemplate here is not precisely
1050  * what we want, but better than using a struct direct.
1051  *
1052  * NB: does not handle corrupted directories.
1053  */
1054 int
1055 ufs_dirempty(struct inode *ip, ino_t parentino, struct ucred *cred)
1056 {
1057         off_t off;
1058         struct dirtemplate dbuf;
1059         struct direct *dp = (struct direct *)&dbuf;
1060         int error, count, namlen;
1061 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2)
1062
1063         for (off = 0; off < ip->i_size; off += dp->d_reclen) {
1064                 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off,
1065                                 UIO_SYSSPACE, IO_NODELOCKED, cred, &count);
1066                 /*
1067                  * Since we read MINDIRSIZ, residual must
1068                  * be 0 unless we're at end of file.
1069                  */
1070                 if (error || count != 0)
1071                         return (0);
1072                 /* avoid infinite loops */
1073                 if (dp->d_reclen == 0)
1074                         return (0);
1075                 /* skip empty entries */
1076                 if (dp->d_ino == 0 || dp->d_ino == WINO)
1077                         continue;
1078                 /* accept only "." and ".." */
1079 #               if (BYTE_ORDER == LITTLE_ENDIAN)
1080                         if (OFSFMT(ITOV(ip)))
1081                                 namlen = dp->d_type;
1082                         else
1083                                 namlen = dp->d_namlen;
1084 #               else
1085                         namlen = dp->d_namlen;
1086 #               endif
1087                 if (namlen > 2)
1088                         return (0);
1089                 if (dp->d_name[0] != '.')
1090                         return (0);
1091                 /*
1092                  * At this point namlen must be 1 or 2.
1093                  * 1 implies ".", 2 implies ".." if second
1094                  * char is also "."
1095                  */
1096                 if (namlen == 1 && dp->d_ino == ip->i_number)
1097                         continue;
1098                 if (dp->d_name[1] == '.' && dp->d_ino == parentino)
1099                         continue;
1100                 return (0);
1101         }
1102         return (1);
1103 }
1104
1105 /*
1106  * Check if source directory is in the path of the target directory.
1107  * Target is supplied locked, source is unlocked.
1108  * The target is always vput before returning.
1109  */
1110 int
1111 ufs_checkpath(struct inode *source, struct inode *target, struct ucred *cred)
1112 {
1113         struct vnode *vp;
1114         int error, rootino, namlen;
1115         struct dirtemplate dirbuf;
1116
1117         vp = ITOV(target);
1118         if (target->i_number == source->i_number) {
1119                 error = EEXIST;
1120                 goto out;
1121         }
1122         rootino = ROOTINO;
1123         error = 0;
1124         if (target->i_number == rootino)
1125                 goto out;
1126
1127         for (;;) {
1128                 if (vp->v_type != VDIR) {
1129                         error = ENOTDIR;
1130                         break;
1131                 }
1132                 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
1133                                 sizeof (struct dirtemplate), (off_t)0,
1134                                 UIO_SYSSPACE, IO_NODELOCKED, cred, NULL);
1135                 if (error != 0)
1136                         break;
1137 #               if (BYTE_ORDER == LITTLE_ENDIAN)
1138                         if (OFSFMT(vp))
1139                                 namlen = dirbuf.dotdot_type;
1140                         else
1141                                 namlen = dirbuf.dotdot_namlen;
1142 #               else
1143                         namlen = dirbuf.dotdot_namlen;
1144 #               endif
1145                 if (namlen != 2 ||
1146                     dirbuf.dotdot_name[0] != '.' ||
1147                     dirbuf.dotdot_name[1] != '.') {
1148                         error = ENOTDIR;
1149                         break;
1150                 }
1151                 if (dirbuf.dotdot_ino == source->i_number) {
1152                         error = EINVAL;
1153                         break;
1154                 }
1155                 if (dirbuf.dotdot_ino == rootino)
1156                         break;
1157                 vput(vp);
1158                 error = VFS_VGET(vp->v_mount, NULL, dirbuf.dotdot_ino, &vp);
1159                 if (error) {
1160                         vp = NULL;
1161                         break;
1162                 }
1163         }
1164
1165 out:
1166         if (error == ENOTDIR)
1167                 kprintf("checkpath: .. not a directory\n");
1168         if (vp != NULL)
1169                 vput(vp);
1170         return (error);
1171 }