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/ext2fs/ext2fs_readwrite.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: ext2fs_readwrite.c,v 1.32 2004/03/22 19:23:08 bouyer Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)ufs_readwrite.c     8.8 (Berkeley) 8/4/94
   32  * Modified for ext2fs by Manuel Bouyer.
   33  */
   34 
   35 /*-
   36  * Copyright (c) 1997 Manuel Bouyer.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 3. All advertising materials mentioning features or use of this software
   47  *    must display the following acknowledgement:
   48  *      This product includes software developed by Manuel Bouyer.
   49  * 4. The name of the author may not be used to endorse or promote products
   50  *    derived from this software without specific prior written permission.
   51  *
   52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   53  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   54  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   55  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   56  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   57  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   58  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   59  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   61  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   62  *
   63  *      @(#)ufs_readwrite.c     8.8 (Berkeley) 8/4/94
   64  * Modified for ext2fs by Manuel Bouyer.
   65  */
   66 
   67 #include <sys/cdefs.h>
   68 __KERNEL_RCSID(0, "$NetBSD: ext2fs_readwrite.c,v 1.32 2004/03/22 19:23:08 bouyer Exp $");
   69 
   70 #include <sys/param.h>
   71 #include <sys/systm.h>
   72 #include <sys/resourcevar.h>
   73 #include <sys/kernel.h>
   74 #include <sys/file.h>
   75 #include <sys/stat.h>
   76 #include <sys/buf.h>
   77 #include <sys/proc.h>
   78 #include <sys/mount.h>
   79 #include <sys/vnode.h>
   80 #include <sys/malloc.h>
   81 #include <sys/signalvar.h>
   82 
   83 #include <ufs/ufs/inode.h>
   84 #include <ufs/ufs/ufs_extern.h>
   85 #include <ufs/ext2fs/ext2fs.h>
   86 #include <ufs/ext2fs/ext2fs_extern.h>
   87 
   88 
   89 #define doclusterread 0 /* XXX underway */
   90 #define doclusterwrite 0
   91 
   92 /*
   93  * Vnode op for reading.
   94  */
   95 /* ARGSUSED */
   96 int
   97 ext2fs_read(v)
   98         void *v;
   99 {
  100         struct vop_read_args /* {
  101                 struct vnode *a_vp;
  102                 struct uio *a_uio;
  103                 int a_ioflag;
  104                 struct ucred *a_cred;
  105         } */ *ap = v;
  106         struct vnode *vp;
  107         struct inode *ip;
  108         struct uio *uio;
  109         struct m_ext2fs *fs;
  110         struct buf *bp;
  111         void *win;
  112         vsize_t bytelen;
  113         daddr_t lbn, nextlbn;
  114         off_t bytesinfile;
  115         long size, xfersize, blkoffset;
  116         int error;
  117 
  118         vp = ap->a_vp;
  119         ip = VTOI(vp);
  120         uio = ap->a_uio;
  121 
  122 #ifdef DIAGNOSTIC
  123         if (uio->uio_rw != UIO_READ)
  124                 panic("%s: mode", "ext2fs_read");
  125 
  126         if (vp->v_type == VLNK) {
  127                 if ((int)ip->i_e2fs_size < vp->v_mount->mnt_maxsymlinklen ||
  128                         (vp->v_mount->mnt_maxsymlinklen == 0 &&
  129                          ip->i_e2fs_nblock == 0))
  130                         panic("%s: short symlink", "ext2fs_read");
  131         } else if (vp->v_type != VREG && vp->v_type != VDIR)
  132                 panic("%s: type %d", "ext2fs_read", vp->v_type);
  133 #endif
  134         fs = ip->i_e2fs;
  135         if ((u_int64_t)uio->uio_offset >
  136                 ((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
  137                 return (EFBIG);
  138         if (uio->uio_resid == 0)
  139                 return (0);
  140         if (uio->uio_offset >= ip->i_e2fs_size)
  141                 return (0);
  142 
  143         if (vp->v_type == VREG) {
  144                 error = 0;
  145                 while (uio->uio_resid > 0) {
  146                         bytelen = MIN(ip->i_e2fs_size - uio->uio_offset,
  147                             uio->uio_resid);
  148 
  149                         if (bytelen == 0) {
  150                                 break;
  151                         }
  152                         win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
  153                             &bytelen, UBC_READ);
  154                         error = uiomove(win, bytelen, uio);
  155                         ubc_release(win, 0);
  156                         if (error) {
  157                                 break;
  158                         }
  159                 }
  160                 goto out;
  161         }
  162 
  163         for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
  164                 if ((bytesinfile = ip->i_e2fs_size - uio->uio_offset) <= 0)
  165                         break;
  166                 lbn = lblkno(fs, uio->uio_offset);
  167                 nextlbn = lbn + 1;
  168                 size = fs->e2fs_bsize;
  169                 blkoffset = blkoff(fs, uio->uio_offset);
  170                 xfersize = fs->e2fs_bsize - blkoffset;
  171                 if (uio->uio_resid < xfersize)
  172                         xfersize = uio->uio_resid;
  173                 if (bytesinfile < xfersize)
  174                         xfersize = bytesinfile;
  175 
  176                 if (lblktosize(fs, nextlbn) >= ip->i_e2fs_size)
  177                         error = bread(vp, lbn, size, NOCRED, &bp);
  178                 else {
  179                         int nextsize = fs->e2fs_bsize;
  180                         error = breadn(vp, lbn,
  181                                 size, &nextlbn, &nextsize, 1, NOCRED, &bp);
  182                 }
  183                 if (error)
  184                         break;
  185 
  186                 /*
  187                  * We should only get non-zero b_resid when an I/O error
  188                  * has occurred, which should cause us to break above.
  189                  * However, if the short read did not cause an error,
  190                  * then we want to ensure that we do not uiomove bad
  191                  * or uninitialized data.
  192                  */
  193                 size -= bp->b_resid;
  194                 if (size < xfersize) {
  195                         if (size == 0)
  196                                 break;
  197                         xfersize = size;
  198                 }
  199                 error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
  200                 if (error)
  201                         break;
  202                 brelse(bp);
  203         }
  204         if (bp != NULL)
  205                 brelse(bp);
  206 
  207 out:
  208         if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
  209                 ip->i_flag |= IN_ACCESS;
  210                 if ((ap->a_ioflag & IO_SYNC) == IO_SYNC)
  211                         error = VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
  212         }
  213         return (error);
  214 }
  215 
  216 /*
  217  * Vnode op for writing.
  218  */
  219 int
  220 ext2fs_write(v)
  221         void *v;
  222 {
  223         struct vop_write_args /* {
  224                 struct vnode *a_vp;
  225                 struct uio *a_uio;
  226                 int a_ioflag;
  227                 struct ucred *a_cred;
  228         } */ *ap = v;
  229         struct vnode *vp;
  230         struct uio *uio;
  231         struct inode *ip;
  232         struct m_ext2fs *fs;
  233         struct buf *bp;
  234         struct proc *p;
  235         daddr_t lbn;
  236         off_t osize;
  237         int blkoffset, error, flags, ioflag, resid, xfersize;
  238         vsize_t bytelen;
  239         void *win;
  240         off_t oldoff;
  241         boolean_t async;
  242         int extended=0;
  243 
  244         ioflag = ap->a_ioflag;
  245         uio = ap->a_uio;
  246         vp = ap->a_vp;
  247         ip = VTOI(vp);
  248         error = 0;
  249 
  250 #ifdef DIAGNOSTIC
  251         if (uio->uio_rw != UIO_WRITE)
  252                 panic("%s: mode", "ext2fs_write");
  253 #endif
  254 
  255         switch (vp->v_type) {
  256         case VREG:
  257                 if (ioflag & IO_APPEND)
  258                         uio->uio_offset = ip->i_e2fs_size;
  259                 if ((ip->i_e2fs_flags & EXT2_APPEND) &&
  260                         uio->uio_offset != ip->i_e2fs_size)
  261                         return (EPERM);
  262                 /* FALLTHROUGH */
  263         case VLNK:
  264                 break;
  265         case VDIR:
  266                 if ((ioflag & IO_SYNC) == 0)
  267                         panic("%s: nonsync dir write", "ext2fs_write");
  268                 break;
  269         default:
  270                 panic("%s: type", "ext2fs_write");
  271         }
  272 
  273         fs = ip->i_e2fs;
  274         if (uio->uio_offset < 0 ||
  275                 (u_int64_t)uio->uio_offset + uio->uio_resid >
  276                 ((u_int64_t)0x80000000 * fs->e2fs_bsize - 1))
  277                 return (EFBIG);
  278         /*
  279          * Maybe this should be above the vnode op call, but so long as
  280          * file servers have no limits, I don't think it matters.
  281          */
  282         p = uio->uio_procp;
  283         if (vp->v_type == VREG && p &&
  284                 uio->uio_offset + uio->uio_resid >
  285                 p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
  286                 psignal(p, SIGXFSZ);
  287                 return (EFBIG);
  288         }
  289         if (uio->uio_resid == 0)
  290                 return (0);
  291 
  292         async = vp->v_mount->mnt_flag & MNT_ASYNC;
  293         resid = uio->uio_resid;
  294         osize = ip->i_e2fs_size;
  295 
  296         if (vp->v_type == VREG) {
  297                 while (uio->uio_resid > 0) {
  298                         oldoff = uio->uio_offset;
  299                         blkoffset = blkoff(fs, uio->uio_offset);
  300                         bytelen = MIN(fs->e2fs_bsize - blkoffset,
  301                             uio->uio_resid);
  302 
  303                         error = ufs_balloc_range(vp, uio->uio_offset,
  304                             bytelen, ap->a_cred, 0);
  305                         if (error) {
  306                                 break;
  307                         }
  308                         win = ubc_alloc(&vp->v_uobj, uio->uio_offset,
  309                             &bytelen, UBC_WRITE);
  310                         error = uiomove(win, bytelen, uio);
  311                         ubc_release(win, 0);
  312                         if (error) {
  313                                 break;
  314                         }
  315 
  316                         /*
  317                          * update UVM's notion of the size now that we've
  318                          * copied the data into the vnode's pages.
  319                          */
  320 
  321                         if (vp->v_size < uio->uio_offset) {
  322                                 uvm_vnp_setsize(vp, uio->uio_offset);
  323                                 extended = 1;
  324                         }
  325 
  326                         /*
  327                          * flush what we just wrote if necessary.
  328                          * XXXUBC simplistic async flushing.
  329                          */
  330 
  331                         if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
  332                                 simple_lock(&vp->v_interlock);
  333                                 error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
  334                                     (uio->uio_offset >> 16) << 16, PGO_CLEANIT);
  335                         }
  336                 }
  337                 if (error == 0 && ioflag & IO_SYNC) {
  338                         simple_lock(&vp->v_interlock);
  339                         error = VOP_PUTPAGES(vp, trunc_page(oldoff),
  340                             round_page(blkroundup(fs, uio->uio_offset)),
  341                             PGO_CLEANIT | PGO_SYNCIO);
  342                 }
  343 
  344                 goto out;
  345         }
  346 
  347         flags = ioflag & IO_SYNC ? B_SYNC : 0;
  348         for (error = 0; uio->uio_resid > 0;) {
  349                 lbn = lblkno(fs, uio->uio_offset);
  350                 blkoffset = blkoff(fs, uio->uio_offset);
  351                 xfersize = MIN(fs->e2fs_bsize - blkoffset, uio->uio_resid);
  352                 if (xfersize < fs->e2fs_bsize)
  353                         flags |= B_CLRBUF;
  354                 else
  355                         flags &= ~B_CLRBUF;
  356                 error = ext2fs_balloc(ip,
  357                     lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
  358                 if (error)
  359                         break;
  360                 if (ip->i_e2fs_size < uio->uio_offset + xfersize) {
  361                         ip->i_e2fs_size = uio->uio_offset + xfersize;
  362                 }
  363                 error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
  364 
  365                 /*
  366                  * update UVM's notion of the size now that we've
  367                  * copied the data into the vnode's pages.
  368                  */
  369 
  370                 if (vp->v_size < uio->uio_offset) {
  371                         uvm_vnp_setsize(vp, uio->uio_offset);
  372                         extended = 1;
  373                 }
  374 
  375                 if (ioflag & IO_SYNC)
  376                         (void)bwrite(bp);
  377                 else if (xfersize + blkoffset == fs->e2fs_bsize)
  378                         bawrite(bp);
  379                 else
  380                         bdwrite(bp);
  381                 if (error || xfersize == 0)
  382                         break;
  383         }
  384 
  385         /*
  386          * If we successfully wrote any data, and we are not the superuser
  387          * we clear the setuid and setgid bits as a precaution against
  388          * tampering.
  389          */
  390 
  391 out:
  392         ip->i_flag |= IN_CHANGE | IN_UPDATE;
  393         if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
  394                 ip->i_e2fs_mode &= ~(ISUID | ISGID);
  395         if (resid > uio->uio_resid)
  396                 VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
  397         if (error) {
  398                 (void) VOP_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred,
  399                     uio->uio_procp);
  400                 uio->uio_offset -= resid - uio->uio_resid;
  401                 uio->uio_resid = resid;
  402         } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
  403                 error = VOP_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
  404         KASSERT(vp->v_size == ip->i_e2fs_size);
  405         return (error);
  406 }

Cache object: e09c2a5b58d2d750c9e9b224442a712a


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