root/ufs/ext2fs/ext2fs_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ext2fs_create
  2. ext2fs_mknod
  3. ext2fs_open
  4. ext2fs_access
  5. ext2fs_getattr
  6. ext2fs_setattr
  7. ext2fs_chmod
  8. ext2fs_chown
  9. ext2fs_remove
  10. ext2fs_link
  11. ext2fs_rename
  12. ext2fs_mkdir
  13. ext2fs_rmdir
  14. ext2fs_symlink
  15. ext2fs_readlink
  16. ext2fs_advlock
  17. ext2fs_makeinode
  18. ext2fs_fsync
  19. ext2fs_reclaim
  20. ext2fsfifo_reclaim

    1 /*      $OpenBSD: ext2fs_vnops.c,v 1.48 2007/06/17 20:15:25 jasper Exp $        */
    2 /*      $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $  */
    3 
    4 /*
    5  * Copyright (c) 1997 Manuel Bouyer.
    6  * Copyright (c) 1982, 1986, 1989, 1993
    7  *      The Regents of the University of California.  All rights reserved.
    8  * (c) UNIX System Laboratories, Inc.
    9  * All or some portions of this file are derived from material licensed
   10  * to the University of California by American Telephone and Telegraph
   11  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   12  * the permission of UNIX System Laboratories, Inc.
   13  *
   14  * Redistribution and use in source and binary forms, with or without
   15  * modification, are permitted provided that the following conditions
   16  * are met:
   17  * 1. Redistributions of source code must retain the above copyright
   18  *    notice, this list of conditions and the following disclaimer.
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  * 3. 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_vnops.c 8.14 (Berkeley) 10/26/94
   39  * Modified for ext2fs by Manuel Bouyer.
   40  */
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/resourcevar.h>
   45 #include <sys/kernel.h>
   46 #include <sys/file.h>
   47 #include <sys/stat.h>
   48 #include <sys/buf.h>
   49 #include <sys/proc.h>
   50 #include <sys/conf.h>
   51 #include <sys/mount.h>
   52 #include <sys/namei.h>
   53 #include <sys/vnode.h>
   54 #include <sys/lockf.h>
   55 #include <sys/malloc.h>
   56 #include <sys/pool.h>
   57 #include <sys/signalvar.h>
   58 
   59 #include <uvm/uvm_extern.h>
   60 
   61 #include <miscfs/fifofs/fifo.h>
   62 #include <miscfs/specfs/specdev.h>
   63 
   64 #include <ufs/ufs/quota.h>
   65 #include <ufs/ufs/inode.h>
   66 #include <ufs/ufs/ufs_extern.h>
   67 #include <ufs/ufs/ufsmount.h>
   68 
   69 #include <ufs/ext2fs/ext2fs.h>
   70 #include <ufs/ext2fs/ext2fs_extern.h>
   71 #include <ufs/ext2fs/ext2fs_dir.h>
   72 
   73 static int ext2fs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *);
   74 static int ext2fs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
   75 
   76 /*
   77  * Create a regular file
   78  */
   79 int
   80 ext2fs_create(void *v)
   81 {
   82         struct vop_create_args *ap = v;
   83         return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, 
   84                                           ap->a_vap->va_mode),
   85                                 ap->a_dvp, ap->a_vpp, ap->a_cnp);
   86 }
   87 
   88 /*
   89  * Mknod vnode call
   90  */
   91 /* ARGSUSED */
   92 int
   93 ext2fs_mknod(void *v)
   94 {
   95         struct vop_mknod_args *ap = v;
   96         struct vattr *vap = ap->a_vap;
   97         struct vnode **vpp = ap->a_vpp;
   98         struct inode *ip;
   99         int error;
  100 
  101         if ((error =
  102                 ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
  103                 ap->a_dvp, vpp, ap->a_cnp)) != 0)
  104                 return (error);
  105         ip = VTOI(*vpp);
  106         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
  107         if (vap->va_rdev != VNOVAL) {
  108                 /*
  109                  * Want to be able to use this to make badblock
  110                  * inodes, so don't truncate the dev number.
  111                  */
  112                 ip->i_e2din->e2di_rdev = h2fs32(vap->va_rdev);
  113         }
  114         /*
  115          * Remove inode so that it will be reloaded by VFS_VGET and
  116          * checked to see if it is an alias of an existing entry in
  117          * the inode cache.
  118          */
  119         vput(*vpp);
  120         (*vpp)->v_type = VNON;
  121         vgone(*vpp);
  122         *vpp = 0;
  123         return (0);
  124 }
  125 
  126 /*
  127  * Open called.
  128  *
  129  * Just check the APPEND flag.
  130  */
  131 /* ARGSUSED */
  132 int
  133 ext2fs_open(void *v)
  134 {
  135         struct vop_open_args *ap = v;
  136 
  137         /*
  138          * Files marked append-only must be opened for appending.
  139          */
  140         if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
  141                 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
  142                 return (EPERM);
  143         return (0);
  144 }
  145 
  146 int
  147 ext2fs_access(void *v)
  148 {
  149         struct vop_access_args *ap = v;
  150         struct vnode *vp = ap->a_vp;
  151         struct inode *ip = VTOI(vp);
  152         mode_t mode = ap->a_mode;
  153 
  154         /* If immutable bit set, nobody gets to write it. */
  155         if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
  156                 return (EPERM);
  157 
  158         return (vaccess(ip->i_e2fs_mode, ip->i_e2fs_uid, ip->i_e2fs_gid, mode,
  159                         ap->a_cred));
  160 }
  161 
  162 /* ARGSUSED */
  163 int
  164 ext2fs_getattr(void *v)
  165 {
  166         struct vop_getattr_args *ap = v;
  167         struct vnode *vp = ap->a_vp;
  168         struct inode *ip = VTOI(vp);
  169         struct vattr *vap = ap->a_vap;
  170         struct timeval tv;
  171 
  172         getmicrotime(&tv);
  173         EXT2FS_ITIMES(ip, &tv, &tv);
  174         /*
  175          * Copy from inode table
  176          */
  177         vap->va_fsid = ip->i_dev;
  178         vap->va_fileid = ip->i_number;
  179         vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
  180         vap->va_nlink = ip->i_e2fs_nlink;
  181         vap->va_uid = ip->i_e2fs_uid;
  182         vap->va_gid = ip->i_e2fs_gid;
  183         vap->va_rdev = (dev_t)fs2h32(ip->i_e2din->e2di_rdev);
  184         vap->va_size = ext2fs_size(ip);
  185         vap->va_atime.tv_sec = ip->i_e2fs_atime;
  186         vap->va_atime.tv_nsec = 0;
  187         vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
  188         vap->va_mtime.tv_nsec = 0;
  189         vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
  190         vap->va_ctime.tv_nsec = 0;
  191 #ifdef EXT2FS_SYSTEM_FLAGS
  192         vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
  193         vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
  194 #else
  195         vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
  196         vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
  197 #endif
  198         vap->va_gen = ip->i_e2fs_gen;
  199         /* this doesn't belong here */
  200         if (vp->v_type == VBLK)
  201                 vap->va_blocksize = BLKDEV_IOSIZE;
  202         else if (vp->v_type == VCHR)
  203                 vap->va_blocksize = MAXBSIZE;
  204         else
  205                 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
  206         vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
  207         vap->va_type = vp->v_type;
  208         vap->va_filerev = ip->i_modrev;
  209         return (0);
  210 }
  211 
  212 /*
  213  * Set attribute vnode op. called from several syscalls
  214  */
  215 int
  216 ext2fs_setattr(void *v)
  217 {
  218         struct vop_setattr_args *ap = v;
  219         struct vattr *vap = ap->a_vap;
  220         struct vnode *vp = ap->a_vp;
  221         struct inode *ip = VTOI(vp);
  222         struct ucred *cred = ap->a_cred;
  223         struct proc *p = ap->a_p;
  224         int error;
  225 
  226         /*
  227          * Check for unsettable attributes.
  228          */
  229         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
  230                 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
  231                 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
  232                 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
  233                 return (EINVAL);
  234         }
  235         if (vap->va_flags != VNOVAL) {
  236                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  237                         return (EROFS);
  238                 if (cred->cr_uid != ip->i_e2fs_uid &&
  239                         (error = suser_ucred(cred)))
  240                         return (error);
  241 #ifdef EXT2FS_SYSTEM_FLAGS
  242                 if (cred->cr_uid == 0) {
  243                         if ((ip->i_e2fs_flags & 
  244                             (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0)
  245                                 return (EPERM);
  246                         ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
  247                         ip->i_e2fs_flags |= 
  248                             (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
  249                             (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
  250                 } else {
  251                         return (EPERM);
  252                 }
  253 #else
  254                 ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
  255                 ip->i_e2fs_flags |= 
  256                     (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
  257                     (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
  258 #endif
  259                 ip->i_flag |= IN_CHANGE;
  260                 if (vap->va_flags & (IMMUTABLE | APPEND))
  261                         return (0);
  262         }
  263         if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
  264                 return (EPERM);
  265         /*
  266          * Go through the fields and update iff not VNOVAL.
  267          */
  268         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  269                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  270                         return (EROFS);
  271                 error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
  272                 if (error)
  273                         return (error);
  274         }
  275         if (vap->va_size != VNOVAL) {
  276                 /*
  277                  * Disallow write attempts on read-only file systems;
  278                  * unless the file is a socket, fifo, or a block or
  279                  * character device resident on the file system.
  280                  */
  281                 switch (vp->v_type) {
  282                 case VDIR:
  283                         return (EISDIR);
  284                 case VLNK:
  285                 case VREG:
  286                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  287                                 return (EROFS);
  288                 default:
  289                         break;
  290                 }
  291                 error = ext2fs_truncate(ip, vap->va_size, 0, cred);
  292                 if (error)
  293                         return (error);
  294         }
  295         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
  296                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  297                         return (EROFS);
  298                 if (cred->cr_uid != ip->i_e2fs_uid &&
  299                         (error = suser_ucred(cred)) &&
  300                         ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
  301                         (error = VOP_ACCESS(vp, VWRITE, cred, p))))
  302                         return (error);
  303                 if (vap->va_atime.tv_sec != VNOVAL)
  304                         if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
  305                                 ip->i_flag |= IN_ACCESS;
  306                 if (vap->va_mtime.tv_sec != VNOVAL)
  307                         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  308                 error = ext2fs_update(ip, &vap->va_atime, &vap->va_mtime, 1);
  309                 if (error)
  310                         return (error);
  311         }
  312         error = 0;
  313         if (vap->va_mode != (mode_t)VNOVAL) {
  314                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  315                         return (EROFS);
  316                 error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p);
  317         }
  318         return (error);
  319 }
  320 
  321 /*
  322  * Change the mode on a file.
  323  * Inode must be locked before calling.
  324  */
  325 static int
  326 ext2fs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct proc *p)
  327 {
  328         struct inode *ip = VTOI(vp);
  329         int error;
  330 
  331         if (cred->cr_uid != ip->i_e2fs_uid && (error = suser_ucred(cred)))
  332                 return (error);
  333         if (cred->cr_uid) {
  334                 if (vp->v_type != VDIR && (mode & S_ISTXT))
  335                         return (EFTYPE);
  336                 if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID))
  337                         return (EPERM);
  338         }
  339         ip->i_e2fs_mode &= ~ALLPERMS;
  340         ip->i_e2fs_mode |= (mode & ALLPERMS);
  341         ip->i_flag |= IN_CHANGE;
  342         if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0)
  343                 (void) uvm_vnp_uncache(vp);
  344         return (0);
  345 }
  346 
  347 /*
  348  * Perform chown operation on inode ip;
  349  * inode must be locked prior to call.
  350  */
  351 static int
  352 ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p)
  353 {
  354         struct inode *ip = VTOI(vp);
  355         uid_t ouid;
  356         gid_t ogid;
  357         int error = 0;
  358 
  359         if (uid == (uid_t)VNOVAL)
  360                 uid = ip->i_e2fs_uid;
  361         if (gid == (gid_t)VNOVAL)
  362                 gid = ip->i_e2fs_gid;
  363         /*
  364          * If we don't own the file, are trying to change the owner
  365          * of the file, or are not a member of the target group,
  366          * the caller must be superuser or the call fails.
  367          */
  368         if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
  369                 (gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) &&
  370                 (error = suser_ucred(cred)))
  371                 return (error);
  372         ogid = ip->i_e2fs_gid;
  373         ouid = ip->i_e2fs_uid;
  374 
  375         ip->i_e2fs_gid = gid;
  376         ip->i_e2fs_uid = uid;
  377         if (ouid != uid || ogid != gid)
  378                 ip->i_flag |= IN_CHANGE;
  379         if (ouid != uid && cred->cr_uid != 0)
  380                 ip->i_e2fs_mode &= ~ISUID;
  381         if (ogid != gid && cred->cr_uid != 0)
  382                 ip->i_e2fs_mode &= ~ISGID;
  383         return (0);
  384 }
  385 
  386 int
  387 ext2fs_remove(void *v)
  388 {
  389         struct vop_remove_args *ap = v;
  390         struct inode *ip;
  391         struct vnode *vp = ap->a_vp;
  392         struct vnode *dvp = ap->a_dvp;
  393         int error;
  394 
  395         ip = VTOI(vp);
  396         if (vp->v_type == VDIR ||
  397                 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
  398                 (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
  399                 error = EPERM;
  400                 goto out;
  401         }
  402         error = ext2fs_dirremove(dvp, ap->a_cnp);
  403         if (error == 0) {
  404                 ip->i_e2fs_nlink--;
  405                 ip->i_flag |= IN_CHANGE;
  406         }
  407 out:
  408         if (dvp == vp)
  409                 vrele(vp);
  410         else
  411                 vput(vp);
  412         vput(dvp);
  413         return (error);
  414 }
  415 
  416 /*
  417  * link vnode call
  418  */
  419 int
  420 ext2fs_link(void *v)
  421 {
  422         struct vop_link_args *ap = v;
  423         struct vnode *dvp = ap->a_dvp;
  424         struct vnode *vp = ap->a_vp;
  425         struct componentname *cnp = ap->a_cnp;
  426         struct proc *p = cnp->cn_proc;
  427         struct inode *ip;
  428         int error;
  429 
  430 #ifdef DIAGNOSTIC
  431         if ((cnp->cn_flags & HASBUF) == 0)
  432                 panic("ext2fs_link: no name");
  433 #endif
  434         if (vp->v_type == VDIR) {
  435                 VOP_ABORTOP(dvp, cnp);
  436                 error = EISDIR;
  437                 goto out2;
  438         }
  439         if (dvp->v_mount != vp->v_mount) {
  440                 VOP_ABORTOP(dvp, cnp);
  441                 error = EXDEV;
  442                 goto out2;
  443         }
  444         if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
  445                 VOP_ABORTOP(dvp, cnp);
  446                 goto out2;
  447         }
  448         ip = VTOI(vp);
  449         if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
  450                 VOP_ABORTOP(dvp, cnp);
  451                 error = EMLINK;
  452                 goto out1;
  453         }
  454         if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
  455                 VOP_ABORTOP(dvp, cnp);
  456                 error = EPERM;
  457                 goto out1;
  458         }
  459         ip->i_e2fs_nlink++;
  460         ip->i_flag |= IN_CHANGE;
  461         error = ext2fs_update(ip, NULL, NULL, 1);
  462         if (!error)
  463                 error = ext2fs_direnter(ip, dvp, cnp);
  464         if (error) {
  465                 ip->i_e2fs_nlink--;
  466                 ip->i_flag |= IN_CHANGE;
  467         }
  468         pool_put(&namei_pool, cnp->cn_pnbuf);
  469 out1:
  470         if (dvp != vp)
  471                 VOP_UNLOCK(vp, 0, p);
  472 out2:
  473         vput(dvp);
  474         return (error);
  475 }
  476 
  477 /*
  478  * Rename system call.
  479  *      rename("foo", "bar");
  480  * is essentially
  481  *      unlink("bar");
  482  *      link("foo", "bar");
  483  *      unlink("foo");
  484  * but ``atomically''.  Can't do full commit without saving state in the
  485  * inode on disk which isn't feasible at this time.  Best we can do is
  486  * always guarantee the target exists.
  487  *
  488  * Basic algorithm is:
  489  *
  490  * 1) Bump link count on source while we're linking it to the
  491  *    target.  This also ensure the inode won't be deleted out
  492  *    from underneath us while we work (it may be truncated by
  493  *    a concurrent `trunc' or `open' for creation).
  494  * 2) Link source to destination.  If destination already exists,
  495  *    delete it first.
  496  * 3) Unlink source reference to inode if still around. If a
  497  *    directory was moved and the parent of the destination
  498  *    is different from the source, patch the ".." entry in the
  499  *    directory.
  500  */
  501 int
  502 ext2fs_rename(void *v)
  503 {
  504         struct vop_rename_args  *ap = v;
  505         struct vnode *tvp = ap->a_tvp;
  506         struct vnode *tdvp = ap->a_tdvp;
  507         struct vnode *fvp = ap->a_fvp;
  508         struct vnode *fdvp = ap->a_fdvp;
  509         struct componentname *tcnp = ap->a_tcnp;
  510         struct componentname *fcnp = ap->a_fcnp;
  511         struct inode *ip, *xp, *dp;
  512         struct proc *p = fcnp->cn_proc;
  513         struct ext2fs_dirtemplate dirbuf;
  514         /* struct timespec ts; */
  515         int doingdirectory = 0, oldparent = 0, newparent = 0;
  516         int error = 0;
  517         u_char namlen;
  518 
  519 #ifdef DIAGNOSTIC
  520         if ((tcnp->cn_flags & HASBUF) == 0 ||
  521             (fcnp->cn_flags & HASBUF) == 0)
  522                 panic("ext2fs_rename: no name");
  523 #endif
  524         /*
  525          * Check for cross-device rename.
  526          */
  527         if ((fvp->v_mount != tdvp->v_mount) ||
  528             (tvp && (fvp->v_mount != tvp->v_mount))) {
  529                 error = EXDEV;
  530 abortit:
  531                 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
  532                 if (tdvp == tvp)
  533                         vrele(tdvp);
  534                 else
  535                         vput(tdvp);
  536                 if (tvp)
  537                         vput(tvp);
  538                 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
  539                 vrele(fdvp);
  540                 vrele(fvp);
  541                 return (error);
  542         }
  543 
  544         /*
  545          * Check if just deleting a link name.
  546          */
  547         if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
  548             (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
  549                 error = EPERM;
  550                 goto abortit;
  551         }
  552         if (fvp == tvp) {
  553                 if (fvp->v_type == VDIR) {
  554                         error = EINVAL;
  555                         goto abortit;
  556                 }
  557 
  558                 /* Release destination completely. */
  559                 VOP_ABORTOP(tdvp, tcnp);
  560                 vput(tdvp);
  561                 vput(tvp);
  562 
  563                 /* Delete source. */
  564                 vrele(fdvp);
  565                 vrele(fvp);
  566                 fcnp->cn_flags &= ~MODMASK;
  567                 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
  568                 if ((fcnp->cn_flags & SAVESTART) == 0)
  569                         panic("ext2fs_rename: lost from startdir");
  570                 fcnp->cn_nameiop = DELETE;
  571                 (void) relookup(fdvp, &fvp, fcnp);
  572                 return (VOP_REMOVE(fdvp, fvp, fcnp));
  573         }
  574         if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
  575                 goto abortit;
  576         dp = VTOI(fdvp);
  577         ip = VTOI(fvp);
  578         if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
  579                 VOP_UNLOCK(fvp, 0, p);
  580                 error = EMLINK;
  581                 goto abortit;
  582         }
  583         if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
  584                 (dp->i_e2fs_flags & EXT2_APPEND)) {
  585                 VOP_UNLOCK(fvp, 0, p);
  586                 error = EPERM;
  587                 goto abortit;
  588         }
  589         if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
  590                 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
  591                 if (!error && tvp)
  592                         error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, 
  593                             tcnp->cn_proc);
  594                 if (error) {
  595                         VOP_UNLOCK(fvp, 0, p);
  596                         error = EACCES;
  597                         goto abortit;
  598                 }
  599                 /*
  600                  * Avoid ".", "..", and aliases of "." for obvious reasons.
  601                  */
  602                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
  603                     dp == ip ||
  604                         (fcnp->cn_flags&ISDOTDOT) ||
  605                         (tcnp->cn_flags & ISDOTDOT) ||
  606                     (ip->i_flag & IN_RENAME)) {
  607                         VOP_UNLOCK(fvp, 0, p);
  608                         error = EINVAL;
  609                         goto abortit;
  610                 }
  611                 ip->i_flag |= IN_RENAME;
  612                 oldparent = dp->i_number;
  613                 doingdirectory++;
  614         }
  615         vrele(fdvp);
  616 
  617         /*
  618          * When the target exists, both the directory
  619          * and target vnodes are returned locked.
  620          */
  621         dp = VTOI(tdvp);
  622         xp = NULL;
  623         if (tvp)
  624                 xp = VTOI(tvp);
  625 
  626         /*
  627          * 1) Bump link count while we're moving stuff
  628          *    around.  If we crash somewhere before
  629          *    completing our work, the link count
  630          *    may be wrong, but correctable.
  631          */
  632         ip->i_e2fs_nlink++;
  633         ip->i_flag |= IN_CHANGE;
  634         if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0) {
  635                 VOP_UNLOCK(fvp, 0, p);
  636                 goto bad;
  637         }
  638 
  639         /*
  640          * If ".." must be changed (ie the directory gets a new
  641          * parent) then the source directory must not be in the
  642          * directory hierarchy above the target, as this would
  643          * orphan everything below the source directory. Also
  644          * the user must have write permission in the source so
  645          * as to be able to change "..". We must repeat the call 
  646          * to namei, as the parent directory is unlocked by the
  647          * call to checkpath().
  648          */
  649         error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
  650         VOP_UNLOCK(fvp, 0, p);
  651         if (oldparent != dp->i_number)
  652                 newparent = dp->i_number;
  653         if (doingdirectory && newparent) {
  654                 if (error)      /* write access check above */
  655                         goto bad;
  656                 if (xp != NULL)
  657                         vput(tvp);
  658                 error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
  659                 if (error != 0)
  660                         goto out;
  661                 if ((tcnp->cn_flags & SAVESTART) == 0)
  662                         panic("ext2fs_rename: lost to startdir");
  663                 if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
  664                         goto out;
  665                 dp = VTOI(tdvp);
  666                 xp = NULL;
  667                 if (tvp)
  668                         xp = VTOI(tvp);
  669         }
  670         /*
  671          * 2) If target doesn't exist, link the target
  672          *    to the source and unlink the source. 
  673          *    Otherwise, rewrite the target directory
  674          *    entry to reference the source inode and
  675          *    expunge the original entry's existence.
  676          */
  677         if (xp == NULL) {
  678                 if (dp->i_dev != ip->i_dev)
  679                         panic("rename: EXDEV");
  680                 /*
  681                  * Account for ".." in new directory.
  682                  * When source and destination have the same
  683                  * parent we don't fool with the link count.
  684                  */
  685                 if (doingdirectory && newparent) {
  686                         if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
  687                                 error = EMLINK;
  688                                 goto bad;
  689                         }
  690                         dp->i_e2fs_nlink++;
  691                         dp->i_flag |= IN_CHANGE;
  692                         if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
  693                                 goto bad;
  694                 }
  695                 error = ext2fs_direnter(ip, tdvp, tcnp);
  696                 if (error != 0) {
  697                         if (doingdirectory && newparent) {
  698                                 dp->i_e2fs_nlink--;
  699                                 dp->i_flag |= IN_CHANGE;
  700                                 (void)ext2fs_update(dp, NULL, NULL, 1);
  701                         }
  702                         goto bad;
  703                 }
  704                 vput(tdvp);
  705         } else {
  706                 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
  707                         panic("rename: EXDEV");
  708                 /*
  709                  * Short circuit rename(foo, foo).
  710                  */
  711                 if (xp->i_number == ip->i_number)
  712                         panic("rename: same file");
  713                 /*
  714                  * If the parent directory is "sticky", then the user must
  715                  * own the parent directory, or the destination of the rename,
  716                  * otherwise the destination may not be changed (except by
  717                  * root). This implements append-only directories.
  718                  */
  719                 if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
  720                     tcnp->cn_cred->cr_uid != dp->i_e2fs_uid &&
  721                     xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) {
  722                         error = EPERM;
  723                         goto bad;
  724                 }
  725                 /*
  726                  * Target must be empty if a directory and have no links
  727                  * to it. Also, ensure source and target are compatible
  728                  * (both directories, or both not directories).
  729                  */
  730                 if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
  731                         if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
  732                                 xp->i_e2fs_nlink > 2) {
  733                                 error = ENOTEMPTY;
  734                                 goto bad;
  735                         }
  736                         if (!doingdirectory) {
  737                                 error = ENOTDIR;
  738                                 goto bad;
  739                         }
  740                         cache_purge(tdvp);
  741                 } else if (doingdirectory) {
  742                         error = EISDIR;
  743                         goto bad;
  744                 }
  745                 error = ext2fs_dirrewrite(dp, ip, tcnp);
  746                 if (error != 0)
  747                         goto bad;
  748                 /*
  749                  * If the target directory is in the same
  750                  * directory as the source directory,
  751                  * decrement the link count on the parent
  752                  * of the target directory.
  753                  */
  754                  if (doingdirectory && !newparent) {
  755                         dp->i_e2fs_nlink--;
  756                         dp->i_flag |= IN_CHANGE;
  757                 }
  758                 vput(tdvp);
  759                 /*
  760                  * Adjust the link count of the target to
  761                  * reflect the dirrewrite above.  If this is
  762                  * a directory it is empty and there are
  763                  * no links to it, so we can squash the inode and
  764                  * any space associated with it.  We disallowed
  765                  * renaming over top of a directory with links to
  766                  * it above, as the remaining link would point to
  767                  * a directory without "." or ".." entries.
  768                  */
  769                 xp->i_e2fs_nlink--;
  770                 if (doingdirectory) {
  771                         if (--xp->i_e2fs_nlink != 0)
  772                                 panic("rename: linked directory");
  773                         error = ext2fs_truncate(xp, (off_t)0, IO_SYNC,
  774                             tcnp->cn_cred);
  775                 }
  776                 xp->i_flag |= IN_CHANGE;
  777                 vput(tvp);
  778                 xp = NULL;
  779         }
  780 
  781         /*
  782          * 3) Unlink the source.
  783          */
  784         fcnp->cn_flags &= ~MODMASK;
  785         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
  786         if ((fcnp->cn_flags & SAVESTART) == 0)
  787                 panic("ext2fs_rename: lost from startdir");
  788         (void) relookup(fdvp, &fvp, fcnp);
  789         if (fvp != NULL) {
  790                 xp = VTOI(fvp);
  791                 dp = VTOI(fdvp);
  792         } else {
  793                 /*
  794                  * From name has disappeared.
  795                  */
  796                 if (doingdirectory)
  797                         panic("ext2fs_rename: lost dir entry");
  798                 vrele(ap->a_fvp);
  799                 return (0);
  800         }
  801         /*
  802          * Ensure that the directory entry still exists and has not
  803          * changed while the new name has been entered. If the source is
  804          * a file then the entry may have been unlinked or renamed. In
  805          * either case there is no further work to be done. If the source
  806          * is a directory then it cannot have been rmdir'ed; its link
  807          * count of three would cause a rmdir to fail with ENOTEMPTY.
  808          * The IRENAME flag ensures that it cannot be moved by another
  809          * rename.
  810          */
  811         if (xp != ip) {
  812                 if (doingdirectory)
  813                         panic("ext2fs_rename: lost dir entry");
  814         } else {
  815                 /*
  816                  * If the source is a directory with a
  817                  * new parent, the link count of the old
  818                  * parent directory must be decremented
  819                  * and ".." set to point to the new parent.
  820                  */
  821                 if (doingdirectory && newparent) {
  822                         dp->i_e2fs_nlink--;
  823                         dp->i_flag |= IN_CHANGE;
  824                         error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
  825                                 sizeof (struct ext2fs_dirtemplate), (off_t)0,
  826                                 UIO_SYSSPACE, IO_NODELOCKED, 
  827                                 tcnp->cn_cred, (size_t *)0, (struct proc *)0);
  828                         if (error == 0) {
  829                                         namlen = dirbuf.dotdot_namlen;
  830                                 if (namlen != 2 ||
  831                                     dirbuf.dotdot_name[0] != '.' ||
  832                                     dirbuf.dotdot_name[1] != '.') {
  833                                         ufs_dirbad(xp, (doff_t)12,
  834                                             "ext2fs_rename: mangled dir");
  835                                 } else {
  836                                         dirbuf.dotdot_ino = h2fs32(newparent);
  837                                         (void) vn_rdwr(UIO_WRITE, fvp,
  838                                             (caddr_t)&dirbuf,
  839                                             sizeof (struct dirtemplate),
  840                                             (off_t)0, UIO_SYSSPACE,
  841                                             IO_NODELOCKED|IO_SYNC,
  842                                             tcnp->cn_cred, (size_t *)0,
  843                                             (struct proc *)0);
  844                                         cache_purge(fdvp);
  845                                 }
  846                         }
  847                 }
  848                 error = ext2fs_dirremove(fdvp, fcnp);
  849                 if (!error) {
  850                         xp->i_e2fs_nlink--;
  851                         xp->i_flag |= IN_CHANGE;
  852                 }
  853                 xp->i_flag &= ~IN_RENAME;
  854         }
  855         if (dp)
  856                 vput(fdvp);
  857         if (xp)
  858                 vput(fvp);
  859         vrele(ap->a_fvp);
  860         return (error);
  861 
  862 bad:
  863         if (xp)
  864                 vput(ITOV(xp));
  865         vput(ITOV(dp));
  866 out:
  867         if (doingdirectory)
  868                 ip->i_flag &= ~IN_RENAME;
  869         if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
  870                 ip->i_e2fs_nlink--;
  871                 ip->i_flag |= IN_CHANGE;
  872                 vput(fvp);
  873         } else
  874                 vrele(fvp);
  875         return (error);
  876 }
  877 
  878 /*
  879  * Mkdir system call
  880  */
  881 int
  882 ext2fs_mkdir(void *v)
  883 {
  884         struct vop_mkdir_args *ap = v;
  885         struct vnode *dvp = ap->a_dvp;
  886         struct vattr *vap = ap->a_vap;
  887         struct componentname *cnp = ap->a_cnp;
  888         struct inode *ip, *dp;
  889         struct vnode *tvp;
  890         struct ext2fs_dirtemplate dirtemplate;
  891         mode_t dmode;
  892         int error;
  893 
  894 #ifdef DIAGNOSTIC
  895         if ((cnp->cn_flags & HASBUF) == 0)
  896                 panic("ext2fs_mkdir: no name");
  897 #endif
  898         dp = VTOI(dvp);
  899         if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
  900                 error = EMLINK;
  901                 goto out;
  902         }
  903         dmode = vap->va_mode & ACCESSPERMS;
  904         dmode |= IFDIR;
  905         /*
  906          * Must simulate part of ext2fs_makeinode here to acquire the inode,
  907          * but not have it entered in the parent directory. The entry is
  908          * made later after writing "." and ".." entries.
  909          */
  910         if ((error = ext2fs_inode_alloc(dp, dmode, cnp->cn_cred, &tvp)) != 0)
  911                 goto out;
  912         ip = VTOI(tvp);
  913         ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
  914         ip->i_e2fs_gid = dp->i_e2fs_gid;
  915         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
  916         ip->i_e2fs_mode = dmode;
  917         tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
  918         ip->i_e2fs_nlink = 2;
  919         error = ext2fs_update(ip, NULL, NULL, 1);
  920 
  921         /*
  922          * Bump link count in parent directory
  923          * to reflect work done below.  Should
  924          * be done before reference is created
  925          * so reparation is possible if we crash.
  926          */
  927         dp->i_e2fs_nlink++;
  928         dp->i_flag |= IN_CHANGE;
  929         if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
  930                 goto bad;
  931 
  932         /* Initialize directory with "." and ".." from static template. */
  933         bzero(&dirtemplate, sizeof(dirtemplate));
  934         dirtemplate.dot_ino = h2fs32(ip->i_number);
  935         dirtemplate.dot_reclen = h2fs16(12);
  936         dirtemplate.dot_namlen = 1;
  937         if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
  938             (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
  939                 dirtemplate.dot_type = EXT2_FT_DIR;
  940         }
  941         dirtemplate.dot_name[0] = '.';
  942         dirtemplate.dotdot_ino = h2fs32(dp->i_number);
  943         dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
  944         dirtemplate.dotdot_namlen = 2;
  945         if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
  946             (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
  947                 dirtemplate.dotdot_type = EXT2_FT_DIR;
  948         }
  949         dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
  950         error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
  951             sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
  952             IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0);
  953         if (error) {
  954                 dp->i_e2fs_nlink--;
  955                 dp->i_flag |= IN_CHANGE;
  956                 goto bad;
  957         }
  958         if (VTOI(dvp)->i_e2fs->e2fs_bsize >
  959                                                         VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
  960                 panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
  961         else {
  962                 error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
  963                 if (error) {
  964                         dp->i_e2fs_nlink--;
  965                         dp->i_flag |= IN_CHANGE;
  966                         goto bad;
  967                 }
  968                 ip->i_flag |= IN_CHANGE;
  969         }
  970 
  971         /* Directory set up, now install its entry in the parent directory. */
  972         error = ext2fs_direnter(ip, dvp, cnp);
  973         if (error != 0) {
  974                 dp->i_e2fs_nlink--;
  975                 dp->i_flag |= IN_CHANGE;
  976         }
  977 bad:
  978         /*
  979          * No need to do an explicit VOP_TRUNCATE here, vrele will do this
  980          * for us because we set the link count to 0.
  981          */
  982         if (error) {
  983                 ip->i_e2fs_nlink = 0;
  984                 ip->i_flag |= IN_CHANGE;
  985                 vput(tvp);
  986         } else
  987                 *ap->a_vpp = tvp;
  988 out:
  989         pool_put(&namei_pool, cnp->cn_pnbuf);
  990         vput(dvp);
  991         return (error);
  992 }
  993 
  994 /*
  995  * Rmdir system call.
  996  */
  997 int
  998 ext2fs_rmdir(void *v)
  999 {
 1000         struct vop_rmdir_args *ap = v;
 1001         struct vnode *vp = ap->a_vp;
 1002         struct vnode *dvp = ap->a_dvp;
 1003         struct componentname *cnp = ap->a_cnp;
 1004         struct inode *ip, *dp;
 1005         int error;
 1006 
 1007         ip = VTOI(vp);
 1008         dp = VTOI(dvp);
 1009         /*
 1010          * No rmdir "." please.
 1011          */
 1012         if (dp == ip) {
 1013                 vrele(dvp);
 1014                 vput(vp);
 1015                 return (EINVAL);
 1016         }
 1017         /*
 1018          * Verify the directory is empty (and valid).
 1019          * (Rmdir ".." won't be valid since
 1020          *  ".." will contain a reference to
 1021          *  the current directory and thus be
 1022          *  non-empty.)
 1023          */
 1024         error = 0;
 1025         if (ip->i_e2fs_nlink != 2 ||
 1026             !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
 1027                 error = ENOTEMPTY;
 1028                 goto out;
 1029         }
 1030         if ((dp->i_e2fs_flags & EXT2_APPEND) ||
 1031                                  (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
 1032                 error = EPERM;
 1033                 goto out;
 1034         }
 1035         /*
 1036          * Delete reference to directory before purging
 1037          * inode.  If we crash in between, the directory
 1038          * will be reattached to lost+found,
 1039          */
 1040         error = ext2fs_dirremove(dvp, cnp);
 1041         if (error != 0)
 1042                 goto out;
 1043         dp->i_e2fs_nlink--;
 1044         dp->i_flag |= IN_CHANGE;
 1045         cache_purge(dvp);
 1046         vput(dvp);
 1047         dvp = NULL;
 1048         /*
 1049          * Truncate inode.  The only stuff left
 1050          * in the directory is "." and "..".  The
 1051          * "." reference is inconsequential since
 1052          * we're quashing it.  The ".." reference
 1053          * has already been adjusted above.  We've
 1054          * removed the "." reference and the reference
 1055          * in the parent directory, but there may be
 1056          * other hard links so decrement by 2 and
 1057          * worry about them later.
 1058          */
 1059         ip->i_e2fs_nlink -= 2;
 1060         error = ext2fs_truncate(ip, (off_t)0, IO_SYNC, cnp->cn_cred);
 1061         cache_purge(ITOV(ip));
 1062 out:
 1063         if (dvp)
 1064                 vput(dvp);
 1065         vput(vp);
 1066         return (error);
 1067 }
 1068 
 1069 /*
 1070  * symlink -- make a symbolic link
 1071  */
 1072 int
 1073 ext2fs_symlink(void *v)
 1074 {
 1075         struct vop_symlink_args *ap = v;
 1076         struct vnode *vp, **vpp = ap->a_vpp;
 1077         struct inode *ip;
 1078         int len, error;
 1079 
 1080         error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
 1081                               vpp, ap->a_cnp);
 1082         if (error)
 1083                 return (error);
 1084         vp = *vpp;
 1085         len = strlen(ap->a_target);
 1086         if (len < vp->v_mount->mnt_maxsymlinklen) {
 1087                 ip = VTOI(vp);
 1088                 bcopy(ap->a_target, (char *)ip->i_e2din->e2di_shortlink, len);
 1089                 error = ext2fs_setsize(ip, len);
 1090                 if (error)
 1091                         goto bad;
 1092                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
 1093         } else
 1094                 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
 1095                     UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
 1096                     (struct proc *)0);
 1097 bad:    
 1098         vput(vp);
 1099         return (error);
 1100 }
 1101 
 1102 /*
 1103  * Return target name of a symbolic link
 1104  */
 1105 int
 1106 ext2fs_readlink(void *v)
 1107 {
 1108         struct vop_readlink_args *ap = v;
 1109         struct vnode *vp = ap->a_vp;
 1110         struct inode *ip = VTOI(vp);
 1111         int isize;
 1112 
 1113         isize = ext2fs_size(ip);
 1114         if (isize < vp->v_mount->mnt_maxsymlinklen ||
 1115             (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
 1116                 uiomove((char *)ip->i_e2din->e2di_shortlink, isize, ap->a_uio);
 1117                 return (0);
 1118         }
 1119         return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
 1120 }
 1121 
 1122 /*
 1123  * Advisory record locking support
 1124  */
 1125 int
 1126 ext2fs_advlock(void *v)
 1127 {
 1128         struct vop_advlock_args *ap = v;
 1129         struct inode *ip = VTOI(ap->a_vp);
 1130 
 1131         return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op,
 1132             ap->a_fl, ap->a_flags));
 1133 }
 1134 
 1135 /*
 1136  * Allocate a new inode.
 1137  */
 1138 int
 1139 ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
 1140     struct componentname *cnp)
 1141 {
 1142         struct inode *ip, *pdir;
 1143         struct vnode *tvp;
 1144         int error;
 1145 
 1146         pdir = VTOI(dvp);
 1147 #ifdef DIAGNOSTIC
 1148         if ((cnp->cn_flags & HASBUF) == 0)
 1149                 panic("ext2fs_makeinode: no name");
 1150 #endif
 1151         *vpp = NULL;
 1152         if ((mode & IFMT) == 0)
 1153                 mode |= IFREG;
 1154 
 1155         if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp)) 
 1156             != 0) {
 1157                 pool_put(&namei_pool, cnp->cn_pnbuf);
 1158                 vput(dvp);
 1159                 return (error);
 1160         }
 1161         ip = VTOI(tvp);
 1162         ip->i_e2fs_gid = pdir->i_e2fs_gid;
 1163         ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
 1164         ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
 1165         ip->i_e2fs_mode = mode;
 1166         tvp->v_type = IFTOVT(mode);     /* Rest init'd in getnewvnode(). */
 1167         ip->i_e2fs_nlink = 1;
 1168         if ((ip->i_e2fs_mode & ISGID) &&
 1169                 !groupmember(ip->i_e2fs_gid, cnp->cn_cred) &&
 1170             suser_ucred(cnp->cn_cred))
 1171                 ip->i_e2fs_mode &= ~ISGID;
 1172 
 1173         /*
 1174          * Make sure inode goes to disk before directory entry.
 1175          */
 1176         if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0)
 1177                 goto bad;
 1178         error = ext2fs_direnter(ip, dvp, cnp);
 1179         if (error != 0)
 1180                 goto bad;
 1181         if ((cnp->cn_flags & SAVESTART) == 0)
 1182                 pool_put(&namei_pool, cnp->cn_pnbuf);
 1183         vput(dvp);
 1184         *vpp = tvp;
 1185         return (0);
 1186 
 1187 bad:
 1188         /*
 1189          * Write error occurred trying to update the inode
 1190          * or the directory so must deallocate the inode.
 1191          */
 1192         pool_put(&namei_pool, cnp->cn_pnbuf);
 1193         vput(dvp);
 1194         ip->i_e2fs_nlink = 0;
 1195         ip->i_flag |= IN_CHANGE;
 1196         tvp->v_type = VNON;
 1197         vput(tvp);
 1198         return (error);
 1199 }
 1200 
 1201 /*
 1202  * Synch an open file.
 1203  */
 1204 /* ARGSUSED */
 1205 int
 1206 ext2fs_fsync(void *v)
 1207 {
 1208         struct vop_fsync_args *ap = v;
 1209         struct vnode *vp = ap->a_vp;
 1210 
 1211         vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
 1212         return (ext2fs_update(VTOI(ap->a_vp), NULL, NULL, 
 1213                     ap->a_waitfor == MNT_WAIT));
 1214 }
 1215 
 1216 /*
 1217  * Reclaim an inode so that it can be used for other purposes.
 1218  */
 1219 int
 1220 ext2fs_reclaim(void *v)
 1221 {
 1222         struct vop_reclaim_args *ap = v;
 1223         struct vnode *vp = ap->a_vp;
 1224         struct inode *ip;
 1225 #ifdef DIAGNOSTIC
 1226         extern int prtactive;
 1227 
 1228         if (prtactive && vp->v_usecount != 0) 
 1229                 vprint("ext2fs_reclaim: pushing active", vp);
 1230 #endif
 1231 
 1232         /*
 1233          * Remove the inode from its hash chain.
 1234          */
 1235         ip = VTOI(vp);
 1236         ufs_ihashrem(ip);
 1237 
 1238         /*
 1239          * Purge old data structures associated with the inode.
 1240          */
 1241         cache_purge(vp);
 1242         if (ip->i_devvp)
 1243                 vrele(ip->i_devvp);
 1244 
 1245         if (ip->i_e2din != NULL)
 1246                 pool_put(&ext2fs_dinode_pool, ip->i_e2din);
 1247 
 1248         pool_put(&ext2fs_inode_pool, ip);
 1249 
 1250         vp->v_data = NULL;
 1251 
 1252         return (0);
 1253 }
 1254 
 1255 /* Global vfs data structures for ext2fs. */
 1256 int (**ext2fs_vnodeop_p)(void *);
 1257 struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
 1258         { &vop_default_desc, vn_default_error },
 1259         { &vop_lookup_desc, ext2fs_lookup },    /* lookup */
 1260         { &vop_create_desc, ext2fs_create },    /* create */
 1261         { &vop_mknod_desc, ext2fs_mknod },              /* mknod */
 1262         { &vop_open_desc, ext2fs_open },                /* open */
 1263         { &vop_close_desc, ufs_close },                 /* close */
 1264         { &vop_access_desc, ext2fs_access },    /* access */
 1265         { &vop_getattr_desc, ext2fs_getattr },  /* getattr */
 1266         { &vop_setattr_desc, ext2fs_setattr },  /* setattr */
 1267         { &vop_read_desc, ext2fs_read },                /* read */
 1268         { &vop_write_desc, ext2fs_write },              /* write */
 1269         { &vop_ioctl_desc, ufs_ioctl },                 /* ioctl */
 1270         { &vop_poll_desc, ufs_poll },           /* poll */
 1271         { &vop_kqfilter_desc, vop_generic_kqfilter },   /* kqfilter */
 1272         { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
 1273         { &vop_remove_desc, ext2fs_remove },    /* remove */
 1274         { &vop_link_desc, ext2fs_link },                /* link */
 1275         { &vop_rename_desc, ext2fs_rename },    /* rename */
 1276         { &vop_mkdir_desc, ext2fs_mkdir },              /* mkdir */
 1277         { &vop_rmdir_desc, ext2fs_rmdir },              /* rmdir */
 1278         { &vop_symlink_desc, ext2fs_symlink },  /* symlink */
 1279         { &vop_readdir_desc, ext2fs_readdir },  /* readdir */
 1280         { &vop_readlink_desc, ext2fs_readlink },/* readlink */
 1281         { &vop_abortop_desc, vop_generic_abortop },             /* abortop */
 1282         { &vop_inactive_desc, ext2fs_inactive },/* inactive */
 1283         { &vop_reclaim_desc, ext2fs_reclaim },  /* reclaim */
 1284         { &vop_lock_desc, ufs_lock },                   /* lock */
 1285         { &vop_unlock_desc, ufs_unlock },               /* unlock */
 1286         { &vop_bmap_desc, ext2fs_bmap },                /* bmap */
 1287         { &vop_strategy_desc, ufs_strategy },   /* strategy */
 1288         { &vop_print_desc, ufs_print },                 /* print */
 1289         { &vop_islocked_desc, ufs_islocked },   /* islocked */
 1290         { &vop_pathconf_desc, ufs_pathconf },   /* pathconf */
 1291         { &vop_advlock_desc, ext2fs_advlock },  /* advlock */
 1292         { &vop_bwrite_desc, vop_generic_bwrite },               /* bwrite */
 1293         { NULL, NULL }
 1294 };
 1295 struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
 1296         { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
 1297 
 1298 int (**ext2fs_specop_p)(void *);
 1299 struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
 1300         { &vop_default_desc, spec_vnoperate },
 1301         { &vop_close_desc, ufsspec_close },             /* close */
 1302         { &vop_access_desc, ext2fs_access },    /* access */
 1303         { &vop_getattr_desc, ext2fs_getattr },  /* getattr */
 1304         { &vop_setattr_desc, ext2fs_setattr },  /* setattr */
 1305         { &vop_read_desc, ufsspec_read },               /* read */
 1306         { &vop_write_desc, ufsspec_write },             /* write */
 1307         { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
 1308         { &vop_inactive_desc, ext2fs_inactive },/* inactive */
 1309         { &vop_reclaim_desc, ext2fs_reclaim },  /* reclaim */
 1310         { &vop_lock_desc, ufs_lock },                   /* lock */
 1311         { &vop_unlock_desc, ufs_unlock },               /* unlock */
 1312         { &vop_print_desc, ufs_print },                 /* print */
 1313         { &vop_islocked_desc, ufs_islocked },   /* islocked */
 1314         { NULL, NULL }
 1315 };
 1316 struct vnodeopv_desc ext2fs_specop_opv_desc =
 1317         { &ext2fs_specop_p, ext2fs_specop_entries };
 1318 
 1319 #ifdef FIFO
 1320 int (**ext2fs_fifoop_p)(void *);
 1321 struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
 1322         { &vop_default_desc, fifo_vnoperate },
 1323         { &vop_close_desc, ufsfifo_close },             /* close */
 1324         { &vop_access_desc, ext2fs_access },    /* access */
 1325         { &vop_getattr_desc, ext2fs_getattr },  /* getattr */
 1326         { &vop_setattr_desc, ext2fs_setattr },  /* setattr */
 1327         { &vop_read_desc, ufsfifo_read },               /* read */
 1328         { &vop_write_desc, ufsfifo_write },             /* write */
 1329         { &vop_fsync_desc, ext2fs_fsync },              /* fsync */
 1330         { &vop_inactive_desc, ext2fs_inactive },/* inactive */
 1331         { &vop_reclaim_desc, ext2fsfifo_reclaim },      /* reclaim */
 1332         { &vop_lock_desc, ufs_lock },                   /* lock */
 1333         { &vop_unlock_desc, ufs_unlock },               /* unlock */
 1334         { &vop_print_desc, ufs_print },                 /* print */
 1335         { &vop_islocked_desc, ufs_islocked },   /* islocked */
 1336         { &vop_bwrite_desc, vop_generic_bwrite },               /* bwrite */
 1337         { NULL, NULL }
 1338 };
 1339 struct vnodeopv_desc ext2fs_fifoop_opv_desc =
 1340         { &ext2fs_fifoop_p, ext2fs_fifoop_entries };
 1341 
 1342 int
 1343 ext2fsfifo_reclaim(void *v)
 1344 {
 1345         fifo_reclaim(v);
 1346         return (ext2fs_reclaim(v));
 1347 }
 1348 #endif /* FIFO */

/* [<][>][^][v][top][bottom][index][help] */