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/fs/smbfs/smbfs_io.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: smbfs_io.c,v 1.16 2003/10/25 08:39:05 christos Exp $   */
    2 
    3 /*
    4  * Copyright (c) 2000-2001, Boris Popov
    5  * 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. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *    This product includes software developed by Boris Popov.
   18  * 4. Neither the name of the author nor the names of any co-contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  * FreeBSD: src/sys/fs/smbfs/smbfs_io.c,v 1.7 2001/12/02 08:56:58 bp Exp
   35  *
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __KERNEL_RCSID(0, "$NetBSD: smbfs_io.c,v 1.16 2003/10/25 08:39:05 christos Exp $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/resourcevar.h>    /* defines plimit structure in proc struct */
   44 #include <sys/kernel.h>
   45 #include <sys/proc.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/buf.h>
   48 #include <sys/mount.h>
   49 #include <sys/namei.h>
   50 #include <sys/vnode.h>
   51 #include <sys/dirent.h>
   52 #include <sys/signalvar.h>
   53 #include <sys/sysctl.h>
   54 #include <sys/vmmeter.h>
   55 
   56 #ifndef __NetBSD__
   57 #include <vm/vm.h>
   58 #if __FreeBSD_version < 400000
   59 #include <vm/vm_prot.h>
   60 #endif
   61 #include <vm/vm_page.h>
   62 #include <vm/vm_extern.h>
   63 #include <vm/vm_object.h>
   64 #include <vm/vm_pager.h>
   65 #include <vm/vnode_pager.h>
   66 #else /* __NetBSD__ */
   67 #include <uvm/uvm.h>
   68 #include <uvm/uvm_extern.h>
   69 #endif /* __NetBSD__ */
   70 
   71 /*
   72 #include <sys/ioccom.h>
   73 */
   74 #include <netsmb/smb.h>
   75 #include <netsmb/smb_conn.h>
   76 #include <netsmb/smb_subr.h>
   77 
   78 #include <fs/smbfs/smbfs.h>
   79 #include <fs/smbfs/smbfs_node.h>
   80 #include <fs/smbfs/smbfs_subr.h>
   81 
   82 /*#define SMBFS_RWGENERIC*/
   83 
   84 #define DE_SIZE (sizeof(struct dirent))
   85 
   86 static int
   87 smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
   88 {
   89         struct dirent de;
   90         struct smb_cred scred;
   91         struct smbfs_fctx *ctx;
   92         struct smbnode *np = VTOSMB(vp);
   93         int error = 0/*, *eofflag = ap->a_eofflag*/;
   94         long offset, limit;
   95 
   96         KASSERT(vp->v_type == VDIR);
   97 
   98         if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0)
   99                 return EINVAL;
  100 
  101         SMBVDEBUG("dirname='%.*s'\n", (int) np->n_nmlen, np->n_name);
  102         smb_makescred(&scred, uio->uio_procp, cred);
  103         offset = uio->uio_offset / DE_SIZE;     /* offset in the directory */
  104         limit = uio->uio_resid / DE_SIZE;
  105 
  106         /* Simulate . */
  107         if (offset < 1) {
  108                 memset(&de, 0, sizeof(de));
  109                 de.d_fileno = np->n_ino;
  110                 de.d_reclen = DE_SIZE;
  111                 de.d_type = DT_DIR;
  112                 de.d_namlen = 1;
  113                 strncpy(de.d_name, ".", 2);
  114                 error = uiomove((caddr_t)&de, sizeof(struct dirent), uio);
  115                 if (error)
  116                         return error;
  117                 limit--;
  118                 offset++;
  119         }
  120         /* Simulate .. */
  121         if (limit > 0 && offset < 2) {
  122                 memset(&de, 0, sizeof(de));
  123                 de.d_fileno = (np->n_parent ? np->n_parent->n_ino : 2);
  124                 de.d_reclen = DE_SIZE;
  125                 de.d_type = DT_DIR;
  126                 de.d_namlen = 2;
  127                 strncpy(de.d_name, "..", 3);
  128                 error = uiomove((caddr_t)&de, sizeof(struct dirent), uio);
  129                 if (error)
  130                         return error;
  131                 limit--;
  132                 offset++;
  133         }
  134 
  135         if (limit == 0)
  136                 return (0);
  137 
  138         if (offset != np->n_dirofs || np->n_dirseq == NULL) {
  139                 SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
  140                 if (np->n_dirseq) {
  141                         smbfs_findclose(np->n_dirseq, &scred);
  142                         np->n_dirseq = NULL;
  143                 }
  144                 np->n_dirofs = 2;
  145                 error = smbfs_findopen(np, "*", 1,
  146                     SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
  147                     &scred, &ctx);
  148                 if (error) {
  149                         SMBVDEBUG("can not open search, error = %d", error);
  150                         return error;
  151                 }
  152                 np->n_dirseq = ctx;
  153         } else
  154                 ctx = np->n_dirseq;
  155 
  156         /* skip entries before offset */
  157         while (np->n_dirofs < offset) {
  158                 error = smbfs_findnext(ctx, offset - np->n_dirofs++, &scred);
  159                 if (error) {
  160                         smbfs_findclose(np->n_dirseq, &scred);
  161                         np->n_dirseq = NULL;
  162                         return (error == ENOENT) ? 0 : error;
  163                 }
  164         }
  165 
  166         for (; limit; limit--, offset++) {
  167                 error = smbfs_findnext(ctx, limit, &scred);
  168                 if (error) {
  169                         if (error == ENOENT)
  170                                 error = 0;
  171                         break;
  172                 }
  173                 np->n_dirofs++;
  174                 memset(&de, 0, DE_SIZE);
  175                 de.d_reclen = DE_SIZE;
  176                 de.d_fileno = ctx->f_attr.fa_ino;
  177                 de.d_type = (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG;
  178                 de.d_namlen = ctx->f_nmlen;
  179                 memcpy(de.d_name, ctx->f_name, de.d_namlen);
  180                 de.d_name[de.d_namlen] = '\0';
  181                 error = uiomove((caddr_t)&de, DE_SIZE, uio);
  182                 if (error)
  183                         break;
  184         }
  185 
  186         return (error);
  187 }
  188 
  189 int
  190 smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
  191 {
  192         struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
  193         struct smbnode *np = VTOSMB(vp);
  194         struct proc *p;
  195         struct vattr vattr;
  196         struct smb_cred scred;
  197         int error;
  198 
  199         KASSERT(vp->v_type == VREG || vp->v_type == VDIR);
  200 
  201         if (uiop->uio_resid == 0)
  202                 return 0;
  203         if (uiop->uio_offset < 0)
  204                 return EINVAL;
  205 /*      if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
  206                 return EFBIG;*/
  207         if (vp->v_type == VDIR) {
  208                 error = smbfs_readvdir(vp, uiop, cred);
  209                 return error;
  210         }
  211 
  212         p = uiop->uio_procp;
  213         if (np->n_flag & NMODIFIED) {
  214                 smbfs_attr_cacheremove(vp);
  215                 error = VOP_GETATTR(vp, &vattr, cred, p);
  216                 if (error)
  217                         return error;
  218                 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
  219         } else {
  220                 error = VOP_GETATTR(vp, &vattr, cred, p);
  221                 if (error)
  222                         return error;
  223                 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
  224                         error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
  225                         if (error)
  226                                 return error;
  227                         np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
  228                 }
  229         }
  230         smb_makescred(&scred, p, cred);
  231         return smb_read(smp->sm_share, np->n_fid, uiop, &scred);
  232 }
  233 
  234 int
  235 smbfs_writevnode(struct vnode *vp, struct uio *uiop,
  236         struct ucred *cred, int ioflag)
  237 {
  238         struct smbmount *smp = VTOSMBFS(vp);
  239         struct smbnode *np = VTOSMB(vp);
  240         struct smb_cred scred;
  241         struct proc *p;
  242         int error = 0;
  243         int extended = 0;
  244         size_t resid = uiop->uio_resid;
  245 
  246         /* vn types other than VREG unsupported */
  247         KASSERT(vp->v_type == VREG);
  248 
  249         SMBVDEBUG("ofs=%lld,resid=%d\n",
  250                 (long long int) uiop->uio_offset,
  251                 uiop->uio_resid);
  252         if (uiop->uio_offset < 0)
  253                 return EINVAL;
  254 /*      if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
  255                 return (EFBIG);*/
  256         p = uiop->uio_procp;
  257         if (ioflag & (IO_APPEND | IO_SYNC)) {
  258                 if (np->n_flag & NMODIFIED) {
  259                         smbfs_attr_cacheremove(vp);
  260                         error = smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
  261                         if (error)
  262                                 return error;
  263                 }
  264                 if (ioflag & IO_APPEND) {
  265 #if notyet
  266                         /*
  267                          * File size can be changed by another client
  268                          */
  269                         smbfs_attr_cacheremove(vp);
  270                         error = VOP_GETATTR(vp, &vattr, cred, td);
  271                         if (error)
  272                                 return (error);
  273 #endif
  274                         uiop->uio_offset = np->n_size;
  275                 }
  276         }
  277         if (uiop->uio_resid == 0)
  278                 return 0;
  279         if (p && uiop->uio_offset + uiop->uio_resid > p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
  280                 psignal(p, SIGXFSZ);
  281                 return EFBIG;
  282         }
  283         smb_makescred(&scred, p, cred);
  284         error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
  285         SMBVDEBUG("after: ofs=%lld,resid=%d,err=%d\n",(long long int)uiop->uio_offset, uiop->uio_resid, error);
  286         if (!error) {
  287                 if (uiop->uio_offset > np->n_size) {
  288                         np->n_size = uiop->uio_offset;
  289                         uvm_vnp_setsize(vp, np->n_size);
  290                         extended = 1;
  291                 }
  292         
  293         }
  294         if (resid > uiop->uio_resid)
  295                 VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
  296         return error;
  297 }
  298 
  299 /*
  300  * Do an I/O operation to/from a cache block.
  301  */
  302 int
  303 smbfs_doio(struct buf *bp, struct ucred *cr, struct proc *p)
  304 {
  305         struct vnode *vp = bp->b_vp;
  306         struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
  307         struct smbnode *np = VTOSMB(vp);
  308         struct uio uio, *uiop = &uio;
  309         struct iovec io;
  310         struct smb_cred scred;
  311         int error = 0;
  312 
  313         uiop->uio_iov = &io;
  314         uiop->uio_iovcnt = 1;
  315         uiop->uio_segflg = UIO_SYSSPACE;
  316         uiop->uio_procp = p;
  317 
  318         smb_makescred(&scred, p, cr);
  319 
  320         if (bp->b_flags == B_READ) {
  321             io.iov_len = uiop->uio_resid = bp->b_bcount;
  322             io.iov_base = bp->b_data;
  323             uiop->uio_rw = UIO_READ;
  324             switch (vp->v_type) {
  325               case VREG:
  326                 uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
  327                 error = smb_read(smp->sm_share, np->n_fid, uiop, &scred);
  328                 if (error)
  329                         break;
  330                 if (uiop->uio_resid) {
  331                         int left = uiop->uio_resid;
  332                         int nread = bp->b_bcount - left;
  333                         if (left > 0)
  334                             bzero((char *)bp->b_data + nread, left);
  335                 }
  336                 break;
  337             default:
  338                 printf("smbfs_doio:  type %x unexpected\n",vp->v_type);
  339                 break;
  340             };
  341             if (error) {
  342                 bp->b_error = error;
  343                 bp->b_flags |= B_ERROR;
  344             }
  345         } else { /* write */
  346                 io.iov_len = uiop->uio_resid = bp->b_bcount;
  347                 uiop->uio_offset = ((off_t)bp->b_blkno) << DEV_BSHIFT;
  348                 io.iov_base = bp->b_data;
  349                 uiop->uio_rw = UIO_WRITE;
  350                 bp->b_flags |= B_BUSY;
  351                 error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
  352                 bp->b_flags &= ~B_BUSY;
  353 
  354 
  355 #ifndef __NetBSD__ /* XXX */
  356                 /*
  357                  * For an interrupted write, the buffer is still valid
  358                  * and the write hasn't been pushed to the server yet,
  359                  * so we can't set BIO_ERROR and report the interruption
  360                  * by setting B_EINTR. For the B_ASYNC case, B_EINTR
  361                  * is not relevant, so the rpc attempt is essentially
  362                  * a noop.  For the case of a V3 write rpc not being
  363                  * committed to stable storage, the block is still
  364                  * dirty and requires either a commit rpc or another
  365                  * write rpc with iomode == NFSV3WRITE_FILESYNC before
  366                  * the block is reused. This is indicated by setting
  367                  * the B_DELWRI and B_NEEDCOMMIT flags.
  368                  */
  369                 if (error == EINTR
  370                     || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
  371                         int s;
  372 
  373                         s = splbio();
  374                         bp->b_flags &= ~(B_INVAL|B_NOCACHE);
  375                         if ((bp->b_flags & B_ASYNC) == 0)
  376                             bp->b_flags |= B_EINTR;
  377                         if ((bp->b_flags & B_PAGING) == 0) {
  378                             bdirty(bp);
  379                             bp->b_flags &= ~B_DONE;
  380                         }
  381                         if ((bp->b_flags & B_ASYNC) == 0)
  382                             bp->b_flags |= B_EINTR;
  383                         splx(s);
  384                 } else {
  385                         if (error) {
  386                                 bp->b_ioflags |= BIO_ERROR;
  387                                 bp->b_error = error;
  388                         }
  389                         bp->b_dirtyoff = bp->b_dirtyend = 0;
  390                 }
  391 #endif /* !__NetBSD__ */
  392         }
  393         bp->b_resid = uiop->uio_resid;
  394         biodone(bp);
  395         return error;
  396 }
  397 
  398 /*
  399  * Flush and invalidate all dirty buffers. If another process is already
  400  * doing the flush, just wait for completion.
  401  */
  402 int
  403 smbfs_vinvalbuf(vp, flags, cred, p, intrflg)
  404         struct vnode *vp;
  405         int flags;
  406         struct ucred *cred;
  407         struct proc *p;
  408         int intrflg;
  409 {
  410         struct smbnode *np = VTOSMB(vp);
  411         int error = 0, slpflag;
  412 
  413         if (intrflg)
  414                 slpflag = PCATCH;
  415         else
  416                 slpflag = 0;
  417 
  418         while (np->n_flag & NFLUSHINPROG) {
  419                 np->n_flag |= NFLUSHWANT;
  420                 error = tsleep((caddr_t)&np->n_flag,
  421                         (PRIBIO + 2) | slpflag, "smfsvinv", 0);
  422                 if (error)
  423                         return (error);
  424         }
  425         np->n_flag |= NFLUSHINPROG;
  426         for(;;) {
  427                 if ((error = vinvalbuf(vp, flags, cred, p, slpflag, 0)) == 0)
  428                         break;
  429 
  430                 if (intrflg && (error == ERESTART || error == EINTR)) {
  431                         np->n_flag &= ~NFLUSHINPROG;
  432                         if (np->n_flag & NFLUSHWANT) {
  433                                 np->n_flag &= ~NFLUSHWANT;
  434                                 wakeup((caddr_t)&np->n_flag);
  435                         }
  436                         return (error);
  437                 }
  438         }
  439         np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
  440         if (np->n_flag & NFLUSHWANT) {
  441                 np->n_flag &= ~NFLUSHWANT;
  442                 wakeup((caddr_t)&np->n_flag);
  443         }
  444         return (error);
  445 }

Cache object: 8f95c928c70c118976b5980019da2141


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