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/ufs/ffs/ffs_vnops.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 /*      $NetBSD: ffs_vnops.c,v 1.104.4.7 2009/04/04 17:27:16 snj Exp $  */
    2 
    3 /*-
    4  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Wasabi Systems, Inc, and by Andrew Doran.
    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  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright (c) 1982, 1986, 1989, 1993
   34  *      The Regents of the University of California.  All rights reserved.
   35  *
   36  * Redistribution and use in source and binary forms, with or without
   37  * modification, are permitted provided that the following conditions
   38  * are met:
   39  * 1. Redistributions of source code must retain the above copyright
   40  *    notice, this list of conditions and the following disclaimer.
   41  * 2. Redistributions in binary form must reproduce the above copyright
   42  *    notice, this list of conditions and the following disclaimer in the
   43  *    documentation and/or other materials provided with the distribution.
   44  * 3. Neither the name of the University nor the names of its contributors
   45  *    may be used to endorse or promote products derived from this software
   46  *    without specific prior written permission.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  *      @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95
   61  */
   62 
   63 #include <sys/cdefs.h>
   64 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.104.4.7 2009/04/04 17:27:16 snj Exp $");
   65 
   66 #if defined(_KERNEL_OPT)
   67 #include "opt_ffs.h"
   68 #include "opt_wapbl.h"
   69 #endif
   70 
   71 #include <sys/param.h>
   72 #include <sys/systm.h>
   73 #include <sys/resourcevar.h>
   74 #include <sys/kernel.h>
   75 #include <sys/file.h>
   76 #include <sys/stat.h>
   77 #include <sys/buf.h>
   78 #include <sys/event.h>
   79 #include <sys/proc.h>
   80 #include <sys/mount.h>
   81 #include <sys/vnode.h>
   82 #include <sys/pool.h>
   83 #include <sys/signalvar.h>
   84 #include <sys/kauth.h>
   85 #include <sys/wapbl.h>
   86 #include <sys/fstrans.h>
   87 
   88 #include <miscfs/fifofs/fifo.h>
   89 #include <miscfs/genfs/genfs.h>
   90 #include <miscfs/specfs/specdev.h>
   91 
   92 #include <ufs/ufs/inode.h>
   93 #include <ufs/ufs/dir.h>
   94 #include <ufs/ufs/ufs_extern.h>
   95 #include <ufs/ufs/ufsmount.h>
   96 #include <ufs/ufs/ufs_wapbl.h>
   97 
   98 #include <ufs/ffs/fs.h>
   99 #include <ufs/ffs/ffs_extern.h>
  100 
  101 #include <uvm/uvm.h>
  102 
  103 /* Global vfs data structures for ufs. */
  104 int (**ffs_vnodeop_p)(void *);
  105 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
  106         { &vop_default_desc, vn_default_error },
  107         { &vop_lookup_desc, ufs_lookup },               /* lookup */
  108         { &vop_create_desc, ufs_create },               /* create */
  109         { &vop_whiteout_desc, ufs_whiteout },           /* whiteout */
  110         { &vop_mknod_desc, ufs_mknod },                 /* mknod */
  111         { &vop_open_desc, ufs_open },                   /* open */
  112         { &vop_close_desc, ufs_close },                 /* close */
  113         { &vop_access_desc, ufs_access },               /* access */
  114         { &vop_getattr_desc, ufs_getattr },             /* getattr */
  115         { &vop_setattr_desc, ufs_setattr },             /* setattr */
  116         { &vop_read_desc, ffs_read },                   /* read */
  117         { &vop_write_desc, ffs_write },                 /* write */
  118         { &vop_ioctl_desc, ufs_ioctl },                 /* ioctl */
  119         { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
  120         { &vop_poll_desc, ufs_poll },                   /* poll */
  121         { &vop_kqfilter_desc, genfs_kqfilter },         /* kqfilter */
  122         { &vop_revoke_desc, ufs_revoke },               /* revoke */
  123         { &vop_mmap_desc, ufs_mmap },                   /* mmap */
  124         { &vop_fsync_desc, ffs_fsync },                 /* fsync */
  125         { &vop_seek_desc, ufs_seek },                   /* seek */
  126         { &vop_remove_desc, ufs_remove },               /* remove */
  127         { &vop_link_desc, ufs_link },                   /* link */
  128         { &vop_rename_desc, ufs_rename },               /* rename */
  129         { &vop_mkdir_desc, ufs_mkdir },                 /* mkdir */
  130         { &vop_rmdir_desc, ufs_rmdir },                 /* rmdir */
  131         { &vop_symlink_desc, ufs_symlink },             /* symlink */
  132         { &vop_readdir_desc, ufs_readdir },             /* readdir */
  133         { &vop_readlink_desc, ufs_readlink },           /* readlink */
  134         { &vop_abortop_desc, ufs_abortop },             /* abortop */
  135         { &vop_inactive_desc, ufs_inactive },           /* inactive */
  136         { &vop_reclaim_desc, ffs_reclaim },             /* reclaim */
  137         { &vop_lock_desc, ffs_lock },                   /* lock */
  138         { &vop_unlock_desc, ffs_unlock },               /* unlock */
  139         { &vop_bmap_desc, ufs_bmap },                   /* bmap */
  140         { &vop_strategy_desc, ufs_strategy },           /* strategy */
  141         { &vop_print_desc, ufs_print },                 /* print */
  142         { &vop_islocked_desc, ffs_islocked },           /* islocked */
  143         { &vop_pathconf_desc, ufs_pathconf },           /* pathconf */
  144         { &vop_advlock_desc, ufs_advlock },             /* advlock */
  145         { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
  146         { &vop_getpages_desc, genfs_getpages },         /* getpages */
  147         { &vop_putpages_desc, genfs_putpages },         /* putpages */
  148         { &vop_openextattr_desc, ffs_openextattr },     /* openextattr */
  149         { &vop_closeextattr_desc, ffs_closeextattr },   /* closeextattr */
  150         { &vop_getextattr_desc, ffs_getextattr },       /* getextattr */
  151         { &vop_setextattr_desc, ffs_setextattr },       /* setextattr */
  152         { &vop_listextattr_desc, ffs_listextattr },     /* listextattr */
  153         { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
  154         { NULL, NULL }
  155 };
  156 const struct vnodeopv_desc ffs_vnodeop_opv_desc =
  157         { &ffs_vnodeop_p, ffs_vnodeop_entries };
  158 
  159 int (**ffs_specop_p)(void *);
  160 const struct vnodeopv_entry_desc ffs_specop_entries[] = {
  161         { &vop_default_desc, vn_default_error },
  162         { &vop_lookup_desc, spec_lookup },              /* lookup */
  163         { &vop_create_desc, spec_create },              /* create */
  164         { &vop_mknod_desc, spec_mknod },                /* mknod */
  165         { &vop_open_desc, spec_open },                  /* open */
  166         { &vop_close_desc, ufsspec_close },             /* close */
  167         { &vop_access_desc, ufs_access },               /* access */
  168         { &vop_getattr_desc, ufs_getattr },             /* getattr */
  169         { &vop_setattr_desc, ufs_setattr },             /* setattr */
  170         { &vop_read_desc, ufsspec_read },               /* read */
  171         { &vop_write_desc, ufsspec_write },             /* write */
  172         { &vop_ioctl_desc, spec_ioctl },                /* ioctl */
  173         { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
  174         { &vop_poll_desc, spec_poll },                  /* poll */
  175         { &vop_kqfilter_desc, spec_kqfilter },          /* kqfilter */
  176         { &vop_revoke_desc, spec_revoke },              /* revoke */
  177         { &vop_mmap_desc, spec_mmap },                  /* mmap */
  178         { &vop_fsync_desc, ffs_fsync },                 /* fsync */
  179         { &vop_seek_desc, spec_seek },                  /* seek */
  180         { &vop_remove_desc, spec_remove },              /* remove */
  181         { &vop_link_desc, spec_link },                  /* link */
  182         { &vop_rename_desc, spec_rename },              /* rename */
  183         { &vop_mkdir_desc, spec_mkdir },                /* mkdir */
  184         { &vop_rmdir_desc, spec_rmdir },                /* rmdir */
  185         { &vop_symlink_desc, spec_symlink },            /* symlink */
  186         { &vop_readdir_desc, spec_readdir },            /* readdir */
  187         { &vop_readlink_desc, spec_readlink },          /* readlink */
  188         { &vop_abortop_desc, spec_abortop },            /* abortop */
  189         { &vop_inactive_desc, ufs_inactive },           /* inactive */
  190         { &vop_reclaim_desc, ffs_reclaim },             /* reclaim */
  191         { &vop_lock_desc, ffs_lock },                   /* lock */
  192         { &vop_unlock_desc, ffs_unlock },               /* unlock */
  193         { &vop_bmap_desc, spec_bmap },                  /* bmap */
  194         { &vop_strategy_desc, spec_strategy },          /* strategy */
  195         { &vop_print_desc, ufs_print },                 /* print */
  196         { &vop_islocked_desc, ffs_islocked },           /* islocked */
  197         { &vop_pathconf_desc, spec_pathconf },          /* pathconf */
  198         { &vop_advlock_desc, spec_advlock },            /* advlock */
  199         { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
  200         { &vop_getpages_desc, spec_getpages },          /* getpages */
  201         { &vop_putpages_desc, spec_putpages },          /* putpages */
  202         { &vop_openextattr_desc, ffs_openextattr },     /* openextattr */
  203         { &vop_closeextattr_desc, ffs_closeextattr },   /* closeextattr */
  204         { &vop_getextattr_desc, ffs_getextattr },       /* getextattr */
  205         { &vop_setextattr_desc, ffs_setextattr },       /* setextattr */
  206         { &vop_listextattr_desc, ffs_listextattr },     /* listextattr */
  207         { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
  208         { NULL, NULL }
  209 };
  210 const struct vnodeopv_desc ffs_specop_opv_desc =
  211         { &ffs_specop_p, ffs_specop_entries };
  212 
  213 int (**ffs_fifoop_p)(void *);
  214 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
  215         { &vop_default_desc, vn_default_error },
  216         { &vop_lookup_desc, fifo_lookup },              /* lookup */
  217         { &vop_create_desc, fifo_create },              /* create */
  218         { &vop_mknod_desc, fifo_mknod },                /* mknod */
  219         { &vop_open_desc, fifo_open },                  /* open */
  220         { &vop_close_desc, ufsfifo_close },             /* close */
  221         { &vop_access_desc, ufs_access },               /* access */
  222         { &vop_getattr_desc, ufs_getattr },             /* getattr */
  223         { &vop_setattr_desc, ufs_setattr },             /* setattr */
  224         { &vop_read_desc, ufsfifo_read },               /* read */
  225         { &vop_write_desc, ufsfifo_write },             /* write */
  226         { &vop_ioctl_desc, fifo_ioctl },                /* ioctl */
  227         { &vop_fcntl_desc, ufs_fcntl },                 /* fcntl */
  228         { &vop_poll_desc, fifo_poll },                  /* poll */
  229         { &vop_kqfilter_desc, fifo_kqfilter },          /* kqfilter */
  230         { &vop_revoke_desc, fifo_revoke },              /* revoke */
  231         { &vop_mmap_desc, fifo_mmap },                  /* mmap */
  232         { &vop_fsync_desc, ffs_fsync },                 /* fsync */
  233         { &vop_seek_desc, fifo_seek },                  /* seek */
  234         { &vop_remove_desc, fifo_remove },              /* remove */
  235         { &vop_link_desc, fifo_link },                  /* link */
  236         { &vop_rename_desc, fifo_rename },              /* rename */
  237         { &vop_mkdir_desc, fifo_mkdir },                /* mkdir */
  238         { &vop_rmdir_desc, fifo_rmdir },                /* rmdir */
  239         { &vop_symlink_desc, fifo_symlink },            /* symlink */
  240         { &vop_readdir_desc, fifo_readdir },            /* readdir */
  241         { &vop_readlink_desc, fifo_readlink },          /* readlink */
  242         { &vop_abortop_desc, fifo_abortop },            /* abortop */
  243         { &vop_inactive_desc, ufs_inactive },           /* inactive */
  244         { &vop_reclaim_desc, ffs_reclaim },             /* reclaim */
  245         { &vop_lock_desc, ffs_lock },                   /* lock */
  246         { &vop_unlock_desc, ffs_unlock },               /* unlock */
  247         { &vop_bmap_desc, fifo_bmap },                  /* bmap */
  248         { &vop_strategy_desc, fifo_strategy },          /* strategy */
  249         { &vop_print_desc, ufs_print },                 /* print */
  250         { &vop_islocked_desc, ffs_islocked },           /* islocked */
  251         { &vop_pathconf_desc, fifo_pathconf },          /* pathconf */
  252         { &vop_advlock_desc, fifo_advlock },            /* advlock */
  253         { &vop_bwrite_desc, vn_bwrite },                /* bwrite */
  254         { &vop_putpages_desc, fifo_putpages },          /* putpages */
  255         { &vop_openextattr_desc, ffs_openextattr },     /* openextattr */
  256         { &vop_closeextattr_desc, ffs_closeextattr },   /* closeextattr */
  257         { &vop_getextattr_desc, ffs_getextattr },       /* getextattr */
  258         { &vop_setextattr_desc, ffs_setextattr },       /* setextattr */
  259         { &vop_listextattr_desc, ffs_listextattr },     /* listextattr */
  260         { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
  261         { NULL, NULL }
  262 };
  263 const struct vnodeopv_desc ffs_fifoop_opv_desc =
  264         { &ffs_fifoop_p, ffs_fifoop_entries };
  265 
  266 #include <ufs/ufs/ufs_readwrite.c>
  267 
  268 int
  269 ffs_fsync(void *v)
  270 {
  271         struct vop_fsync_args /* {
  272                 struct vnode *a_vp;
  273                 kauth_cred_t a_cred;
  274                 int a_flags;
  275                 off_t a_offlo;
  276                 off_t a_offhi;
  277                 struct lwp *a_l;
  278         } */ *ap = v;
  279         struct buf *bp;
  280         int num, error, i;
  281         struct indir ia[NIADDR + 1];
  282         int bsize;
  283         daddr_t blk_high;
  284         struct vnode *vp;
  285 #ifdef WAPBL
  286         struct mount *mp;
  287 #endif
  288 
  289         vp = ap->a_vp;
  290 
  291         fstrans_start(vp->v_mount, FSTRANS_LAZY);
  292         /*
  293          * XXX no easy way to sync a range in a file with softdep.
  294          */
  295         if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(vp) ||
  296             (vp->v_type != VREG)) {
  297                 int flags = ap->a_flags;
  298                 error = ffs_full_fsync(vp, flags);
  299                 goto out;
  300         }
  301 
  302         bsize = vp->v_mount->mnt_stat.f_iosize;
  303         blk_high = ap->a_offhi / bsize;
  304         if (ap->a_offhi % bsize != 0)
  305                 blk_high++;
  306 
  307         /*
  308          * First, flush all pages in range.
  309          */
  310 
  311         mutex_enter(&vp->v_interlock);
  312         error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
  313             round_page(ap->a_offhi), PGO_CLEANIT |
  314             ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
  315         if (error) {
  316                 goto out;
  317         }
  318 
  319 #ifdef WAPBL
  320         mp = wapbl_vptomp(vp);
  321         if (mp->mnt_wapbl) {
  322                 /*
  323                  * Don't bother writing out metadata if the syncer is
  324                  * making the request.  We will let the sync vnode
  325                  * write it out in a single burst through a call to
  326                  * VFS_SYNC().
  327                  */
  328                 if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) {
  329                         fstrans_done(vp->v_mount);
  330                         return 0;
  331                 }
  332                 error = 0;
  333                 if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag &
  334                     (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY |
  335                                  IN_MODIFIED | IN_ACCESSED)) {
  336                         error = UFS_WAPBL_BEGIN(mp);
  337                         if (error) {
  338                                 fstrans_done(vp->v_mount);
  339                                 return error;
  340                         }
  341                         error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE |
  342                             ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0));
  343                         UFS_WAPBL_END(mp);
  344                 }
  345                 if (error || (ap->a_flags & FSYNC_NOLOG) != 0) {
  346                         fstrans_done(vp->v_mount);
  347                         return error;
  348                 }
  349                 error = wapbl_flush(mp->mnt_wapbl, 0);
  350                 fstrans_done(vp->v_mount);
  351                 return error;
  352         }
  353 #endif /* WAPBL */
  354 
  355         /*
  356          * Then, flush indirect blocks.
  357          */
  358 
  359         if (blk_high >= NDADDR) {
  360                 error = ufs_getlbns(vp, blk_high, ia, &num);
  361                 if (error)
  362                         goto out;
  363 
  364                 mutex_enter(&bufcache_lock);
  365                 for (i = 0; i < num; i++) {
  366                         if ((bp = incore(vp, ia[i].in_lbn)) == NULL)
  367                                 continue;
  368                         if ((bp->b_cflags & BC_BUSY) != 0 ||
  369                             (bp->b_oflags & BO_DELWRI) == 0)
  370                                 continue;
  371                         bp->b_cflags |= BC_BUSY | BC_VFLUSH;
  372                         mutex_exit(&bufcache_lock);
  373                         bawrite(bp);
  374                         mutex_enter(&bufcache_lock);
  375                 }
  376                 mutex_exit(&bufcache_lock);
  377         }
  378 
  379         if (ap->a_flags & FSYNC_WAIT) {
  380                 mutex_enter(&vp->v_interlock);
  381                 while (vp->v_numoutput > 0)
  382                         cv_wait(&vp->v_cv, &vp->v_interlock);
  383                 mutex_exit(&vp->v_interlock);
  384         }
  385 
  386         error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE |
  387             (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT)
  388             ? UPDATE_WAIT : 0));
  389 
  390         if (error == 0 && ap->a_flags & FSYNC_CACHE) {
  391                 int l = 0;
  392                 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
  393                         curlwp->l_cred);
  394         }
  395 
  396 out:
  397         fstrans_done(vp->v_mount);
  398         return error;
  399 }
  400 
  401 /*
  402  * Synch an open file.  Called for VOP_FSYNC().
  403  */
  404 /* ARGSUSED */
  405 int
  406 ffs_full_fsync(struct vnode *vp, int flags)
  407 {
  408         struct buf *bp, *nbp;
  409         int error, passes, skipmeta, inodedeps_only, waitfor, i;
  410         struct mount *mp;
  411 
  412         KASSERT(VTOI(vp) != NULL);
  413         KASSERT(vp->v_tag == VT_UFS);
  414 
  415         error = 0;
  416 
  417         mp = vp->v_mount;
  418         if (vp->v_type == VBLK && vp->v_specmountpoint != NULL) {
  419                 mp = vp->v_specmountpoint;
  420                 if ((mp->mnt_flag & MNT_SOFTDEP) != 0)
  421                         softdep_fsync_mountdev(vp);
  422         } else {
  423                 mp = vp->v_mount;
  424         }
  425 
  426         mutex_enter(&vp->v_interlock);
  427 
  428         inodedeps_only = DOINGSOFTDEP(vp) && (flags & FSYNC_RECLAIM)
  429             && UVM_OBJ_IS_CLEAN(&vp->v_uobj) && LIST_EMPTY(&vp->v_dirtyblkhd);
  430 
  431         /*
  432          * Flush all dirty data associated with the vnode.
  433          */
  434         if (vp->v_type == VREG || vp->v_type == VBLK) {
  435                 int pflags = PGO_ALLPAGES | PGO_CLEANIT;
  436 
  437                 if ((flags & FSYNC_WAIT))
  438                         pflags |= PGO_SYNCIO;
  439                 if (vp->v_type == VREG &&
  440                     fstrans_getstate(mp) == FSTRANS_SUSPENDING)
  441                         pflags |= PGO_FREE;
  442                 error = VOP_PUTPAGES(vp, 0, 0, pflags);
  443                 if (error)
  444                         return error;
  445         } else {
  446                 mutex_exit(&vp->v_interlock);
  447         }
  448 
  449 #ifdef WAPBL
  450         if (mp && mp->mnt_wapbl) {
  451                 /*
  452                  * Don't bother writing out metadata if the syncer is
  453                  * making the request.  We will let the sync vnode
  454                  * write it out in a single burst through a call to
  455                  * VFS_SYNC().
  456                  */
  457                 if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0)
  458                         return 0;
  459 
  460                 if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE
  461                     | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) {
  462                         error = UFS_WAPBL_BEGIN(mp);
  463                         if (error)
  464                                 return error;
  465                         error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE |
  466                             ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0));
  467                         UFS_WAPBL_END(mp);
  468                 }
  469                 if (error || (flags & FSYNC_NOLOG) != 0)
  470                         return error;
  471 
  472                 /*
  473                  * Don't flush the log if the vnode being flushed
  474                  * contains no dirty buffers that could be in the log.
  475                  */
  476                 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
  477                         error = wapbl_flush(mp->mnt_wapbl, 0);
  478                         if (error)
  479                                 return error;
  480                 }
  481 
  482                 if ((flags & FSYNC_WAIT) != 0) {
  483                         mutex_enter(&vp->v_interlock);
  484                         while (vp->v_numoutput != 0)
  485                                 cv_wait(&vp->v_cv, &vp->v_interlock);
  486                         mutex_exit(&vp->v_interlock);
  487                 }
  488 
  489                 return error;
  490         }
  491 #endif /* WAPBL */
  492 
  493         /*
  494          * Write out metadata for non-logging file systems.  This block can
  495          * be simplified once softdep goes.
  496          */
  497         passes = NIADDR + 1;
  498         skipmeta = 0;
  499         if (flags & FSYNC_WAIT)
  500                 skipmeta = 1;
  501 
  502 loop:
  503         mutex_enter(&bufcache_lock);
  504         LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
  505                 bp->b_cflags &= ~BC_SCANNED;
  506         }
  507         for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
  508                 nbp = LIST_NEXT(bp, b_vnbufs);
  509                 if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
  510                         continue;
  511                 if ((bp->b_oflags & BO_DELWRI) == 0)
  512                         panic("ffs_fsync: not dirty");
  513                 if (skipmeta && bp->b_lblkno < 0)
  514                         continue;
  515                 bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
  516                 mutex_exit(&bufcache_lock);
  517                 /*
  518                  * On our final pass through, do all I/O synchronously
  519                  * so that we can find out if our flush is failing
  520                  * because of write errors.
  521                  */
  522                 if (passes > 0 || !(flags & FSYNC_WAIT))
  523                         (void) bawrite(bp);
  524                 else if ((error = bwrite(bp)) != 0)
  525                         return (error);
  526                 /*
  527                  * Since we unlocked during the I/O, we need
  528                  * to start from a known point.
  529                  */
  530                 mutex_enter(&bufcache_lock);
  531                 nbp = LIST_FIRST(&vp->v_dirtyblkhd);
  532         }
  533         mutex_exit(&bufcache_lock);
  534         if (skipmeta) {
  535                 skipmeta = 0;
  536                 goto loop;
  537         }
  538 
  539         if ((flags & FSYNC_WAIT) != 0) {
  540                 mutex_enter(&vp->v_interlock);
  541                 while (vp->v_numoutput) {
  542                         cv_wait(&vp->v_cv, &vp->v_interlock);
  543                 }
  544                 mutex_exit(&vp->v_interlock);
  545 
  546                 /*
  547                  * Ensure that any filesystem metadata associated
  548                  * with the vnode has been written.
  549                  */
  550                 if ((error = softdep_sync_metadata(vp)) != 0)
  551                         return (error);
  552 
  553                 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
  554                         /*
  555                         * Block devices associated with filesystems may
  556                         * have new I/O requests posted for them even if
  557                         * the vnode is locked, so no amount of trying will
  558                         * get them clean. Thus we give block devices a
  559                         * good effort, then just give up. For all other file
  560                         * types, go around and try again until it is clean.
  561                         */
  562                         if (passes > 0) {
  563                                 passes--;
  564                                 goto loop;
  565                         }
  566 #ifdef DIAGNOSTIC
  567                         if (vp->v_type != VBLK)
  568                                 vprint("ffs_fsync: dirty", vp);
  569 #endif
  570                 }
  571         }
  572 
  573         if (inodedeps_only)
  574                 waitfor = 0;
  575         else
  576                 waitfor = (flags & FSYNC_WAIT) != 0 ? UPDATE_WAIT : 0;
  577         error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE | waitfor);
  578 
  579         if (error == 0 && (flags & FSYNC_CACHE) != 0) {
  580                 (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE,
  581                     kauth_cred_get());
  582         }
  583 
  584         return error;
  585 }
  586 
  587 /*
  588  * Reclaim an inode so that it can be used for other purposes.
  589  */
  590 int
  591 ffs_reclaim(void *v)
  592 {
  593         struct vop_reclaim_args /* {
  594                 struct vnode *a_vp;
  595                 struct lwp *a_l;
  596         } */ *ap = v;
  597         struct vnode *vp = ap->a_vp;
  598         struct inode *ip = VTOI(vp);
  599         struct mount *mp = vp->v_mount;
  600         struct ufsmount *ump = ip->i_ump;
  601         void *data;
  602         int error;
  603 
  604         fstrans_start(mp, FSTRANS_LAZY);
  605         if ((error = ufs_reclaim(vp)) != 0) {
  606                 fstrans_done(mp);
  607                 return (error);
  608         }
  609         if (ip->i_din.ffs1_din != NULL) {
  610                 if (ump->um_fstype == UFS1)
  611                         pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
  612                 else
  613                         pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din);
  614         }
  615         /*
  616          * To interlock with ffs_sync().
  617          */
  618         genfs_node_destroy(vp);
  619         mutex_enter(&vp->v_interlock);
  620         data = vp->v_data;
  621         vp->v_data = NULL;
  622         mutex_exit(&vp->v_interlock);
  623 
  624         /*
  625          * XXX MFS ends up here, too, to free an inode.  Should we create
  626          * XXX a separate pool for MFS inodes?
  627          */
  628         pool_cache_put(ffs_inode_cache, data);
  629         fstrans_done(mp);
  630         return (0);
  631 }
  632 
  633 #if 0
  634 int
  635 ffs_getpages(void *v)
  636 {
  637         struct vop_getpages_args /* {
  638                 struct vnode *a_vp;
  639                 voff_t a_offset;
  640                 struct vm_page **a_m;
  641                 int *a_count;
  642                 int a_centeridx;
  643                 vm_prot_t a_access_type;
  644                 int a_advice;
  645                 int a_flags;
  646         } */ *ap = v;
  647         struct vnode *vp = ap->a_vp;
  648         struct inode *ip = VTOI(vp);
  649         struct fs *fs = ip->i_fs;
  650 
  651         /*
  652          * don't allow a softdep write to create pages for only part of a block.
  653          * the dependency tracking requires that all pages be in memory for
  654          * a block involved in a dependency.
  655          */
  656 
  657         if (ap->a_flags & PGO_OVERWRITE &&
  658             (blkoff(fs, ap->a_offset) != 0 ||
  659              blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) &&
  660             DOINGSOFTDEP(ap->a_vp)) {
  661                 if ((ap->a_flags & PGO_LOCKED) == 0) {
  662                         mutex_exit(&vp->v_interlock);
  663                 }
  664                 return EINVAL;
  665         }
  666         return genfs_getpages(v);
  667 }
  668 #endif
  669 
  670 /*
  671  * Return the last logical file offset that should be written for this file
  672  * if we're doing a write that ends at "size".
  673  */
  674 
  675 void
  676 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
  677 {
  678         struct inode *ip = VTOI(vp);
  679         struct fs *fs = ip->i_fs;
  680         daddr_t olbn, nlbn;
  681 
  682         olbn = lblkno(fs, ip->i_size);
  683         nlbn = lblkno(fs, size);
  684         if (nlbn < NDADDR && olbn <= nlbn) {
  685                 *eobp = fragroundup(fs, size);
  686         } else {
  687                 *eobp = blkroundup(fs, size);
  688         }
  689 }
  690 
  691 int
  692 ffs_openextattr(void *v)
  693 {
  694         struct vop_openextattr_args /* {
  695                 struct vnode *a_vp;
  696                 kauth_cred_t a_cred;
  697                 struct proc *a_p;
  698         } */ *ap = v;
  699         struct inode *ip = VTOI(ap->a_vp);
  700         struct fs *fs = ip->i_fs;
  701 
  702         /* Not supported for UFS1 file systems. */
  703         if (fs->fs_magic == FS_UFS1_MAGIC)
  704                 return (EOPNOTSUPP);
  705 
  706         /* XXX Not implemented for UFS2 file systems. */
  707         return (EOPNOTSUPP);
  708 }
  709 
  710 int
  711 ffs_closeextattr(void *v)
  712 {
  713         struct vop_closeextattr_args /* {
  714                 struct vnode *a_vp;
  715                 int a_commit;
  716                 kauth_cred_t a_cred;
  717                 struct proc *a_p;
  718         } */ *ap = v;
  719         struct inode *ip = VTOI(ap->a_vp);
  720         struct fs *fs = ip->i_fs;
  721 
  722         /* Not supported for UFS1 file systems. */
  723         if (fs->fs_magic == FS_UFS1_MAGIC)
  724                 return (EOPNOTSUPP);
  725 
  726         /* XXX Not implemented for UFS2 file systems. */
  727         return (EOPNOTSUPP);
  728 }
  729 
  730 int
  731 ffs_getextattr(void *v)
  732 {
  733         struct vop_getextattr_args /* {
  734                 struct vnode *a_vp;
  735                 int a_attrnamespace;
  736                 const char *a_name;
  737                 struct uio *a_uio;
  738                 size_t *a_size;
  739                 kauth_cred_t a_cred;
  740                 struct proc *a_p;
  741         } */ *ap = v;
  742         struct vnode *vp = ap->a_vp;
  743         struct inode *ip = VTOI(vp);
  744         struct fs *fs = ip->i_fs;
  745 
  746         if (fs->fs_magic == FS_UFS1_MAGIC) {
  747 #ifdef UFS_EXTATTR
  748                 int error;
  749 
  750                 fstrans_start(vp->v_mount, FSTRANS_SHARED);
  751                 error = ufs_getextattr(ap);
  752                 fstrans_done(vp->v_mount);
  753                 return error;
  754 #else
  755                 return (EOPNOTSUPP);
  756 #endif
  757         }
  758 
  759         /* XXX Not implemented for UFS2 file systems. */
  760         return (EOPNOTSUPP);
  761 }
  762 
  763 int
  764 ffs_setextattr(void *v)
  765 {
  766         struct vop_setextattr_args /* {
  767                 struct vnode *a_vp;
  768                 int a_attrnamespace;
  769                 const char *a_name;
  770                 struct uio *a_uio;
  771                 kauth_cred_t a_cred;
  772                 struct proc *a_p;
  773         } */ *ap = v;
  774         struct vnode *vp = ap->a_vp;
  775         struct inode *ip = VTOI(vp);
  776         struct fs *fs = ip->i_fs;
  777 
  778         if (fs->fs_magic == FS_UFS1_MAGIC) {
  779 #ifdef UFS_EXTATTR
  780                 int error;
  781 
  782                 fstrans_start(vp->v_mount, FSTRANS_SHARED);
  783                 error = ufs_setextattr(ap);
  784                 fstrans_done(vp->v_mount);
  785                 return error;
  786 #else
  787                 return (EOPNOTSUPP);
  788 #endif
  789         }
  790 
  791         /* XXX Not implemented for UFS2 file systems. */
  792         return (EOPNOTSUPP);
  793 }
  794 
  795 int
  796 ffs_listextattr(void *v)
  797 {
  798         struct vop_listextattr_args /* {
  799                 struct vnode *a_vp;
  800                 int a_attrnamespace;
  801                 struct uio *a_uio;
  802                 size_t *a_size;
  803                 kauth_cred_t a_cred;
  804                 struct proc *a_p;
  805         } */ *ap = v;
  806         struct inode *ip = VTOI(ap->a_vp);
  807         struct fs *fs = ip->i_fs;
  808 
  809         /* Not supported for UFS1 file systems. */
  810         if (fs->fs_magic == FS_UFS1_MAGIC)
  811                 return (EOPNOTSUPP);
  812 
  813         /* XXX Not implemented for UFS2 file systems. */
  814         return (EOPNOTSUPP);
  815 }
  816 
  817 int
  818 ffs_deleteextattr(void *v)
  819 {
  820         struct vop_deleteextattr_args /* {
  821                 struct vnode *a_vp;
  822                 int a_attrnamespace;
  823                 kauth_cred_t a_cred;
  824                 struct proc *a_p;
  825         } */ *ap = v;
  826         struct vnode *vp = ap->a_vp;
  827         struct inode *ip = VTOI(vp);
  828         struct fs *fs = ip->i_fs;
  829 
  830         if (fs->fs_magic == FS_UFS1_MAGIC) {
  831 #ifdef UFS_EXTATTR
  832                 int error;
  833 
  834                 fstrans_start(vp->v_mount, FSTRANS_SHARED);
  835                 error = ufs_deleteextattr(ap);
  836                 fstrans_done(vp->v_mount);
  837                 return error;
  838 #else
  839                 return (EOPNOTSUPP);
  840 #endif
  841         }
  842 
  843         /* XXX Not implemented for UFS2 file systems. */
  844         return (EOPNOTSUPP);
  845 }
  846 
  847 /*
  848  * Lock the node.
  849  */
  850 int
  851 ffs_lock(void *v)
  852 {
  853         struct vop_lock_args /* {
  854                 struct vnode *a_vp;
  855                 int a_flags;
  856         } */ *ap = v;
  857         struct vnode *vp = ap->a_vp;
  858         struct mount *mp = vp->v_mount;
  859         int flags = ap->a_flags;
  860 
  861         if ((flags & LK_INTERLOCK) != 0) {
  862                 mutex_exit(&vp->v_interlock);
  863                 flags &= ~LK_INTERLOCK;
  864         }
  865 
  866         /*
  867          * Fake lock during file system suspension.
  868          */
  869         if ((vp->v_type == VREG || vp->v_type == VDIR) &&
  870             fstrans_is_owner(mp) &&
  871             fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
  872                 return 0;
  873         }
  874 
  875         return (vlockmgr(vp->v_vnlock, flags));
  876 }
  877 
  878 /*
  879  * Unlock the node.
  880  */
  881 int
  882 ffs_unlock(void *v)
  883 {
  884         struct vop_unlock_args /* {
  885                 struct vnode *a_vp;
  886                 int a_flags;
  887         } */ *ap = v;
  888         struct vnode *vp = ap->a_vp;
  889         struct mount *mp = vp->v_mount;
  890 
  891         KASSERT(ap->a_flags == 0);
  892 
  893         /*
  894          * Fake unlock during file system suspension.
  895          */
  896         if ((vp->v_type == VREG || vp->v_type == VDIR) &&
  897             fstrans_is_owner(mp) &&
  898             fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
  899                 return 0;
  900         }
  901         return (vlockmgr(vp->v_vnlock, LK_RELEASE));
  902 }
  903 
  904 /*
  905  * Return whether or not the node is locked.
  906  */
  907 int
  908 ffs_islocked(void *v)
  909 {
  910         struct vop_islocked_args /* {
  911                 struct vnode *a_vp;
  912         } */ *ap = v;
  913         struct vnode *vp = ap->a_vp;
  914 
  915         return (vlockstatus(vp->v_vnlock));
  916 }

Cache object: 5530c7f960ced71072c197b75a53180a


[ 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.