The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_cnode.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 #include <sys/param.h>
   26 #include <sys/systm.h>
   27 #include <sys/proc.h>
   28 #include <sys/vnode.h>
   29 #include <sys/mount.h>
   30 #include <sys/kernel.h>
   31 #include <sys/malloc.h>
   32 #include <sys/ubc.h>
   33 #include <sys/quota.h>
   34 
   35 #include <miscfs/specfs/specdev.h>
   36 #include <miscfs/fifofs/fifo.h>
   37 
   38 #include <hfs/hfs.h>
   39 #include <hfs/hfs_catalog.h>
   40 #include <hfs/hfs_cnode.h>
   41 #include <hfs/hfs_quota.h>
   42 
   43 extern int prtactive;
   44 
   45 
   46 extern void     hfs_relnamehints(struct cnode *dcp);
   47 
   48 
   49 /*
   50  * Last reference to an cnode.  If necessary, write or delete it.
   51  */
   52 __private_extern__
   53 int
   54 hfs_inactive(ap)
   55         struct vop_inactive_args /* {
   56                 struct vnode *a_vp;
   57         } */ *ap;
   58 {
   59         struct vnode *vp = ap->a_vp;
   60         struct cnode *cp = VTOC(vp);
   61         struct hfsmount *hfsmp = VTOHFS(vp);
   62         struct proc *p = ap->a_p;
   63         struct timeval tv;
   64         int error = 0;
   65         int recycle = 0;
   66         int forkcount = 0;
   67         int truncated = 0;
   68         int started_tr = 0, grabbed_lock = 0;
   69         cat_cookie_t cookie;
   70         int cat_reserve = 0;
   71 
   72         if (prtactive && vp->v_usecount != 0)
   73                 vprint("hfs_inactive: pushing active", vp);
   74 
   75         /*
   76          * Ignore nodes related to stale file handles.
   77          */
   78         if (cp->c_mode == 0)
   79                 goto out;
   80 
   81         if (hfsmp->hfs_flags & HFS_READ_ONLY)
   82                 goto out;
   83 
   84         if (cp->c_datafork)
   85                 ++forkcount;
   86         if (cp->c_rsrcfork)
   87                 ++forkcount;
   88 
   89         /* If needed, get rid of any fork's data for a deleted file */
   90         if ((vp->v_type == VREG) && (cp->c_flag & C_DELETED)) {
   91                 if (VTOF(vp)->ff_blocks != 0) {
   92                         error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p);
   93                         if (error)
   94                                 goto out;
   95                         truncated = 1;
   96                 }
   97                 recycle = 1;
   98         }
   99 
  100         /*
  101          * Check for a postponed deletion.
  102          * (only delete cnode when the last fork goes inactive)
  103          */
  104         if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) {                     
  105                 /*
  106                  * Mark cnode in transit so that no one can get this 
  107                  * cnode from cnode hash.
  108                  */
  109                 SET(cp->c_flag, C_TRANSIT);
  110                 cp->c_flag &= ~C_DELETED;
  111                 cp->c_rdev = 0;
  112 
  113                 // XXXdbg
  114                 hfs_global_shared_lock_acquire(hfsmp);
  115                 grabbed_lock = 1;
  116                 if (hfsmp->jnl) {
  117                     if (journal_start_transaction(hfsmp->jnl) != 0) {
  118                                 error = EINVAL;
  119                                 goto out;
  120                     }
  121                     started_tr = 1;
  122                 }
  123 
  124                 /*
  125                  * Reserve some space in the Catalog file.
  126                  */
  127                 if ((error = cat_preflight(hfsmp, CAT_DELETE, &cookie, p))) {
  128                         goto out;
  129                 }
  130                 cat_reserve = 1;
  131 
  132 
  133                 /* Lock catalog b-tree */
  134                 error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
  135                 if (error) goto out;
  136 
  137                 if (cp->c_blocks > 0)
  138                         printf("hfs_inactive: attempting to delete a non-empty file!");
  139 
  140                 /*
  141                  * The descriptor name may be zero,
  142                  * in which case the fileid is used.
  143                  */
  144                 error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr);
  145                 
  146                 if (error && truncated && (error != ENXIO))
  147                         printf("hfs_inactive: couldn't delete a truncated file!");
  148 
  149                 /* Update HFS Private Data dir */
  150                 if (error == 0) {
  151                         hfsmp->hfs_privdir_attr.ca_entries--;
  152                         (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
  153                                 &hfsmp->hfs_privdir_attr, NULL, NULL);
  154                 }
  155 
  156                 /* Unlock catalog b-tree */
  157                 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  158                 if (error) goto out;
  159 
  160 #if QUOTA
  161                 (void)hfs_chkiq(cp, -1, NOCRED, 0);
  162 #endif /* QUOTA */
  163 
  164                 cp->c_mode = 0;
  165                 cp->c_flag |= C_NOEXISTS | C_CHANGE | C_UPDATE;
  166 
  167                 if (error == 0)
  168                         hfs_volupdate(hfsmp, VOL_RMFILE, 0);
  169         }
  170 
  171         if (cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) {
  172                 tv = time;
  173                 // if the only thing being updated is the access time
  174                 // then set the modified bit too so that update will
  175                 // flush it to disk.  otherwise it'll get dropped.
  176                 if ((cp->c_flag & C_CHANGEMASK) == C_ACCESS) {
  177                     cp->c_flag |= C_MODIFIED;
  178                 }
  179                 VOP_UPDATE(vp, &tv, &tv, 0);
  180         }
  181 out:
  182         if (cat_reserve)
  183                 cat_postflight(hfsmp, &cookie, p);
  184 
  185         // XXXdbg - have to do this because a goto could have come here
  186         if (started_tr) {
  187             journal_end_transaction(hfsmp->jnl);
  188             started_tr = 0;
  189         }
  190         if (grabbed_lock) {
  191                 hfs_global_shared_lock_release(hfsmp);
  192         }
  193 
  194         VOP_UNLOCK(vp, 0, p);
  195         /*
  196          * If we are done with the vnode, reclaim it
  197          * so that it can be reused immediately.
  198          */
  199         if (cp->c_mode == 0 || recycle)
  200                 vrecycle(vp, (struct slock *)0, p);
  201 
  202         return (error);
  203 }
  204 
  205 
  206 /*
  207  * Reclaim a cnode so that it can be used for other purposes.
  208  */
  209 __private_extern__
  210 int
  211 hfs_reclaim(ap)
  212         struct vop_reclaim_args /* {
  213                 struct vnode *a_vp;
  214         } */ *ap;
  215 {
  216         struct vnode *vp = ap->a_vp;
  217         struct cnode *cp = VTOC(vp);
  218         struct vnode *devvp = NULL;
  219         struct filefork *fp = NULL;
  220         struct filefork *altfp = NULL;
  221         int i;
  222 
  223         if (prtactive && vp->v_usecount != 0)
  224                 vprint("hfs_reclaim(): pushing active", vp);
  225 
  226         /*
  227          * Keep track of an inactive hot file.
  228          */
  229         (void) hfs_addhotfile(vp);
  230 
  231         devvp = cp->c_devvp;            /* For later releasing */
  232 
  233         /*
  234          * Find file fork for this vnode (if any)
  235          * Also check if another fork is active
  236          */
  237         if ((fp = cp->c_datafork) && (cp->c_vp == vp)) {
  238                 cp->c_datafork = NULL;
  239                 cp->c_vp = NULL;
  240                 altfp = cp->c_rsrcfork;
  241         } else if ((fp = cp->c_rsrcfork) && (cp->c_rsrc_vp == vp)) {
  242                 cp->c_rsrcfork = NULL;
  243                 cp->c_rsrc_vp = NULL;
  244                 if (VPARENT(vp) == cp->c_vp) {
  245                     cp->c_flag &= ~C_VPREFHELD;
  246                 }
  247                 altfp = cp->c_datafork;
  248         } else {
  249                 cp->c_vp = NULL;
  250                 fp = NULL;
  251                 altfp = NULL;
  252         }
  253 
  254         /*
  255          * On the last fork, remove the cnode from its hash chain.
  256          */
  257         if (altfp == NULL)
  258                 hfs_chashremove(cp);
  259 
  260         /* Release the file fork and related data (can block) */
  261         if (fp) {
  262                 fp->ff_cp = NULL;
  263                 /* Dump cached symlink data */
  264                 if ((vp->v_type == VLNK) && (fp->ff_symlinkptr != NULL)) {
  265                         FREE(fp->ff_symlinkptr, M_TEMP);
  266                         fp->ff_symlinkptr = NULL;
  267                 }
  268                 FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK);
  269                 fp = NULL;
  270         }
  271 
  272         /*
  273          * Purge old data structures associated with the cnode.
  274          */
  275         cache_purge(vp);
  276         if (devvp && altfp == NULL) {
  277                 cp->c_devvp = NULL;
  278                 vrele(devvp);
  279         }
  280 
  281         vp->v_data = NULL;
  282 
  283         /* 
  284          * If there was only one active fork then we can release the cnode.
  285          */
  286         if (altfp == NULL) {
  287 #if QUOTA
  288                 for (i = 0; i < MAXQUOTAS; i++) {
  289                         if (cp->c_dquot[i] != NODQUOT) {
  290                                 dqreclaim(vp, cp->c_dquot[i]);
  291                                 cp->c_dquot[i] = NODQUOT;
  292                         }
  293                 }
  294 #endif /* QUOTA */
  295                 /* 
  296                  * Free any left over directory indices
  297                  */
  298                 if (vp->v_type == VDIR)
  299                         hfs_relnamehints(cp);
  300 
  301                 /* 
  302                  * If the descriptor has a name then release it
  303                  */
  304                 if (cp->c_desc.cd_flags & CD_HASBUF) {
  305                         char *nameptr;
  306 
  307                         nameptr = cp->c_desc.cd_nameptr;
  308                         cp->c_desc.cd_nameptr = 0;
  309                         cp->c_desc.cd_flags &= ~CD_HASBUF;
  310                         cp->c_desc.cd_namelen = 0;
  311                         remove_name(nameptr);
  312                 }
  313                 CLR(cp->c_flag, (C_ALLOC | C_TRANSIT));
  314                 if (ISSET(cp->c_flag, C_WALLOC) || ISSET(cp->c_flag, C_WTRANSIT))
  315                         wakeup(cp);
  316                 FREE_ZONE(cp, sizeof(struct cnode), M_HFSNODE);
  317 
  318         }
  319 
  320         return (0);
  321 }
  322 
  323 
  324 /*
  325  * get a cnode
  326  *
  327  * called by hfs_lookup and hfs_vget (descp == NULL)
  328  *
  329  * returns a locked vnode for cnode for given cnid/fileid
  330  */
  331 __private_extern__
  332 int
  333 hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wantrsrc,
  334                   struct cat_attr *attrp, struct cat_fork *forkp, struct vnode **vpp)
  335 {
  336         dev_t dev = hfsmp->hfs_raw_dev;
  337         struct vnode *vp = NULL;
  338         struct vnode *rvp = NULL;
  339         struct vnode *new_vp = NULL;
  340         struct cnode *cp = NULL;
  341         struct proc *p = current_proc();
  342         int retval = E_NONE;
  343 
  344         /* Check if unmount in progress */
  345         if (HFSTOVFS(hfsmp)->mnt_kern_flag & MNTK_UNMOUNT) {
  346                 *vpp = NULL;
  347                 return (EPERM);
  348         }
  349 
  350         /*
  351          * Check the hash for an active cnode
  352          */
  353         cp = hfs_chashget(dev, cnid, wantrsrc, &vp, &rvp);
  354         if (cp != NULL) {
  355                 /* hide open files that have been deleted */
  356                 if ((hfsmp->hfs_privdir_desc.cd_cnid != 0)
  357                 &&  (cp->c_parentcnid == hfsmp->hfs_privdir_desc.cd_cnid)
  358                 &&  (cp->c_nlink == 0)) {
  359                         retval = ENOENT;
  360                         goto exit;
  361                 }
  362 
  363                 /* Hide private journal files */
  364                 if (hfsmp->jnl &&
  365                         (cp->c_parentcnid == kRootDirID) &&
  366                         ((cp->c_cnid == hfsmp->hfs_jnlfileid) ||
  367                         (cp->c_cnid == hfsmp->hfs_jnlinfoblkid))) {
  368                     retval = ENOENT;
  369                         goto exit;
  370                 }
  371          
  372                 if (wantrsrc && rvp != NULL) {
  373                         vp = rvp;
  374                         rvp = NULL;
  375                         goto done;
  376                 }
  377                 if (!wantrsrc && vp != NULL) {
  378                         /* Hardlinks need an updated catalog descriptor */
  379                         if (descp && cp->c_flag & C_HARDLINK) {
  380                                 replace_desc(cp, descp);
  381                         }
  382                         /* We have a vnode so we're done. */
  383                         goto done;
  384                 }
  385         }
  386 
  387         /*
  388          * There was no active vnode so get a new one.
  389          * Use the existing cnode (if any).
  390          */
  391         if (descp != NULL) {
  392                 /*
  393                  * hfs_lookup case, use descp, attrp and forkp
  394                  */
  395                 retval = hfs_getnewvnode(hfsmp, cp, descp, wantrsrc, attrp,
  396                                 forkp, &new_vp);
  397         } else {
  398                 struct cat_desc cndesc = {0};
  399                 struct cat_attr cnattr = {0};
  400                 struct cat_fork cnfork = {0};
  401 
  402                 /*
  403                  * hfs_vget case, need to lookup entry (by file id)
  404                  */
  405                 if (cnid == kRootParID) {
  406                         static char hfs_rootname[] = "/";
  407 
  408                         cndesc.cd_nameptr = &hfs_rootname[0];
  409                         cndesc.cd_namelen = 1;
  410                         cndesc.cd_parentcnid = kRootParID;
  411                         cndesc.cd_cnid = kRootParID;
  412                         cndesc.cd_flags = CD_ISDIR;
  413         
  414                         cnattr.ca_fileid = kRootParID;
  415                         cnattr.ca_nlink = 2;
  416                         cnattr.ca_entries = 1;
  417                         cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO);
  418                 } else {
  419                         /* Lock catalog b-tree */
  420                         retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p);
  421                         if (retval)
  422                                 goto exit;
  423         
  424                         retval = cat_idlookup(hfsmp, cnid, &cndesc, &cnattr, &cnfork);
  425         
  426                         /* Unlock catalog b-tree */
  427                         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  428                         if (retval)
  429                                 goto exit;
  430         
  431                         /* Hide open files that have been deleted */
  432                         if ((hfsmp->hfs_privdir_desc.cd_cnid != 0) &&
  433                             (cndesc.cd_parentcnid == hfsmp->hfs_privdir_desc.cd_cnid) &&
  434                             (cnattr.ca_nlink == 0)) {
  435                                 cat_releasedesc(&cndesc);
  436                                 retval = ENOENT;
  437                                 goto exit;
  438                         }
  439                 }
  440                 
  441                 retval = hfs_getnewvnode(hfsmp, cp, &cndesc, 0, &cnattr, &cnfork, &new_vp);
  442 
  443                 /* Hardlinks may need an updated catalog descriptor */
  444                 if (retval == 0
  445                 &&  new_vp
  446                 &&  (VTOC(new_vp)->c_flag & C_HARDLINK)
  447                 &&  cndesc.cd_nameptr
  448                 &&  cndesc.cd_namelen > 0) {
  449                         replace_desc(VTOC(new_vp), &cndesc);
  450                 }
  451 
  452                 cat_releasedesc(&cndesc);
  453         }
  454 
  455 exit:
  456         /* Release reference taken on opposite vnode (if any). */
  457         if (vp)
  458                 vrele(vp);
  459         else if (rvp)
  460                 vrele(rvp);
  461 
  462         if (retval) {
  463                 *vpp = NULL;
  464                 return (retval);
  465         }
  466         vp = new_vp;
  467 done:
  468         /* The cnode's vnode should be in vp. */
  469         if (vp == NULL)
  470                 panic("hfs_getcnode: missing vp!");
  471 
  472         if (UBCISVALID(vp))
  473                 UBCINFOCHECK("hfs_getcnode", vp);
  474         *vpp = vp;
  475         return (0);
  476 }
  477 
  478 
  479 /*
  480  * hfs_getnewvnode - get new default vnode
  481  *
  482  * the vnode is returned locked
  483  */
  484 extern int (**hfs_vnodeop_p) (void *);
  485 extern int (**hfs_specop_p)  (void *);
  486 extern int (**hfs_fifoop_p)  (void *);
  487 
  488 __private_extern__
  489 int
  490 hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp,
  491         struct cat_desc *descp, int wantrsrc,
  492         struct cat_attr *attrp, struct cat_fork *forkp,
  493         struct vnode **vpp)
  494 {
  495         struct mount *mp = HFSTOVFS(hfsmp);
  496         struct vnode *vp = NULL;
  497         struct vnode *rvp = NULL;
  498         struct vnode *new_vp = NULL;
  499         struct cnode *cp2 = NULL;
  500         struct filefork *fp = NULL;
  501         int allocated = 0;
  502         int i;
  503         int retval;
  504         dev_t dev;
  505         struct proc *p = current_proc();
  506 #if 0
  507         /* Bail when unmount is in progress */
  508         if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
  509                 *vpp = NULL;
  510                 return (EPERM);
  511         }
  512 #endif
  513 
  514 #if !FIFO
  515         if (IFTOVT(attrp->ca_mode) == VFIFO) {
  516                 *vpp = NULL;
  517                 return (EOPNOTSUPP);
  518         }
  519 #endif
  520         dev = hfsmp->hfs_raw_dev;
  521 
  522         /* If no cnode was passed in then create one */
  523         if (cp == NULL) {
  524                 MALLOC_ZONE(cp2, struct cnode *, sizeof(struct cnode),
  525                         M_HFSNODE, M_WAITOK);
  526                 bzero(cp2, sizeof(struct cnode));
  527                 allocated = 1;
  528                 SET(cp2->c_flag, C_ALLOC);
  529                 cp2->c_cnid = descp->cd_cnid;
  530                 cp2->c_fileid = attrp->ca_fileid;
  531                 if (cp2->c_fileid == 0) {
  532                         FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE);
  533                         *vpp = NULL;
  534                         return (ENOENT);
  535                 }
  536                 cp2->c_dev = dev;
  537                 lockinit(&cp2->c_lock, PINOD, "cnode", 0, 0);
  538                 (void) lockmgr(&cp2->c_lock, LK_EXCLUSIVE, (struct slock *)0, p);
  539                 /*
  540                  * There were several blocking points since we first
  541                  * checked the hash. Now that we're through blocking,
  542                  * check the hash again in case we're racing for the
  543                  * same cnode.
  544                  */
  545                 cp = hfs_chashget(dev, attrp->ca_fileid, wantrsrc, &vp, &rvp);
  546                 if (cp != NULL) {
  547                         /* We lost the race - use the winner's cnode */
  548                         FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE);
  549                         allocated = 0;
  550                         if (wantrsrc && rvp != NULL) {
  551                                 *vpp = rvp;
  552                                 return (0);
  553                         }
  554                         if (!wantrsrc && vp != NULL) {
  555                                 *vpp = vp;
  556                                 return (0);
  557                         }
  558                 } else /* allocated */ {
  559                         cp = cp2;
  560                         hfs_chashinsert(cp);
  561                 }
  562         }
  563 
  564         /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
  565         if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &new_vp))) {
  566                 if (allocated) {
  567                         hfs_chashremove(cp);
  568                         if (ISSET(cp->c_flag, C_WALLOC)) {
  569                                 CLR(cp->c_flag, C_WALLOC);
  570                                 wakeup(cp);
  571                         }
  572                         FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE);
  573                         allocated = 0;
  574                 } else if (rvp) {
  575                         vput(rvp);
  576                 } else if (vp) {
  577                         vput(vp);
  578                 }
  579                 *vpp = NULL;
  580                 return (retval);
  581         }
  582         if (allocated) {
  583                 bcopy(attrp, &cp->c_attr, sizeof(struct cat_attr));
  584                 bcopy(descp, &cp->c_desc, sizeof(struct cat_desc));
  585         }
  586         new_vp->v_data = cp;
  587         if (wantrsrc && S_ISREG(cp->c_mode))
  588                 cp->c_rsrc_vp = new_vp;
  589         else
  590                 cp->c_vp = new_vp;
  591 
  592         /* Release reference taken on opposite vnode (if any). */
  593         if (rvp)
  594                 vrele(rvp);
  595         if (vp)
  596                 vrele(vp);
  597 
  598         vp = new_vp;
  599         vp->v_ubcinfo = UBC_NOINFO;
  600 
  601         /*
  602          * If this is a new cnode then initialize it using descp and attrp...
  603          */
  604         if (allocated) {
  605                 /* The name was inherited so clear descriptor state... */
  606                 descp->cd_namelen = 0;
  607                 descp->cd_nameptr = NULL;
  608                 descp->cd_flags &= ~CD_HASBUF;
  609 
  610                 /* Tag hardlinks */
  611                 if (IFTOVT(cp->c_mode) == VREG &&
  612                     (descp->cd_cnid != attrp->ca_fileid)) {
  613                         cp->c_flag |= C_HARDLINK;
  614                 }
  615 
  616                 /* Take one dev reference for each non-directory cnode */
  617                 if (IFTOVT(cp->c_mode) != VDIR) {
  618                         cp->c_devvp = hfsmp->hfs_devvp;
  619                         VREF(cp->c_devvp);
  620                 }
  621 #if QUOTA
  622                 for (i = 0; i < MAXQUOTAS; i++)
  623                         cp->c_dquot[i] = NODQUOT;
  624 #endif /* QUOTA */
  625         }
  626 
  627         if (IFTOVT(cp->c_mode) != VDIR) {
  628                 if (forkp && attrp->ca_blocks < forkp->cf_blocks)
  629                         panic("hfs_getnewvnode: bad ca_blocks (too small)");
  630                 /*
  631                  * Allocate and initialize a file fork...
  632                  */
  633                 MALLOC_ZONE(fp, struct filefork *, sizeof(struct filefork),
  634                         M_HFSFORK, M_WAITOK);
  635                 bzero(fp, sizeof(struct filefork));
  636                 fp->ff_cp = cp;
  637                 if (forkp)
  638                         bcopy(forkp, &fp->ff_data, sizeof(struct cat_fork));
  639                 rl_init(&fp->ff_invalidranges);
  640                 if (wantrsrc) {
  641                         if (cp->c_rsrcfork != NULL)
  642                                 panic("stale rsrc fork");
  643                         cp->c_rsrcfork = fp;
  644                 } else {
  645                         if (cp->c_datafork != NULL)
  646                                 panic("stale data fork");
  647                         cp->c_datafork = fp;
  648                 }
  649         }
  650 
  651         /*
  652          * Finish vnode initialization.
  653          * Setting the v_type 'stamps' the vnode as 'complete',
  654          * so should be done almost last. 
  655          * 
  656          * At this point the vnode should be locked and fully
  657          * allocated. And ready to be used or accessed. (though
  658          * having it locked prevents most of this, it can still
  659          * be accessed through lists and hashes).
  660          */
  661         vp->v_type = IFTOVT(cp->c_mode);
  662 
  663         /* Tag system files */
  664         if ((descp->cd_flags & CD_ISMETA) && (vp->v_type == VREG))
  665                 vp->v_flag |= VSYSTEM;
  666         /* Tag root directory */
  667         if (cp->c_cnid == kRootDirID)
  668                 vp->v_flag |= VROOT;
  669 
  670         if ((vp->v_type == VREG) && !(vp->v_flag & VSYSTEM)
  671             && (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))) {
  672                 ubc_info_init(vp);
  673         } else {
  674                 vp->v_ubcinfo = UBC_NOINFO;
  675         }
  676 
  677         if (vp->v_type == VCHR || vp->v_type == VBLK) {
  678                 struct vnode *nvp;
  679 
  680                 vp->v_op = hfs_specop_p;
  681                 if ((nvp = checkalias(vp, cp->c_rdev, mp))) {
  682                         /*
  683                          * Discard unneeded vnode, but save its cnode.
  684                          * Note that the lock is carried over in the
  685                          * cnode to the replacement vnode.
  686                          */
  687                         nvp->v_data = vp->v_data;
  688                         vp->v_data = NULL;
  689                         vp->v_op = spec_vnodeop_p;
  690                         vrele(vp);
  691                         vgone(vp);
  692                         /*
  693                          * Reinitialize aliased cnode.
  694                          * Assume its not a resource fork.
  695                          */
  696                         cp->c_vp = nvp;                         
  697                         vp = nvp;
  698                 }
  699         } else if (vp->v_type == VFIFO) {
  700 #if FIFO
  701                 vp->v_op = hfs_fifoop_p;
  702 #endif
  703         }
  704 
  705         /*
  706          * Stop tracking an active hot file.
  707          */
  708         (void) hfs_removehotfile(vp);
  709 
  710         /* Vnode is now initialized - see if anyone was waiting for it. */
  711         CLR(cp->c_flag, C_ALLOC);
  712         if (ISSET(cp->c_flag, C_WALLOC)) {
  713                 CLR(cp->c_flag, C_WALLOC);
  714                 wakeup((caddr_t)cp);
  715         }
  716 
  717         *vpp = vp;
  718         return (0);
  719 }
  720 

Cache object: 902935cc9e5af2cc9c2fe8b2cb0fd5d1


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.