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_node.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_node.c,v 1.21 2004/02/29 12:17:39 jdolecek 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_node.c,v 1.5 2001/12/20 22:42:26 dillon Exp
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: smbfs_node.c,v 1.21 2004/02/29 12:17:39 jdolecek Exp $");
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/lock.h>
   44 #include <sys/malloc.h>
   45 #include <sys/mount.h>
   46 #include <sys/namei.h>
   47 #include <sys/proc.h>
   48 #include <sys/queue.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/time.h>
   51 #include <sys/vnode.h>
   52 
   53 #include <netsmb/smb.h>
   54 #include <netsmb/smb_conn.h>
   55 #include <netsmb/smb_subr.h>
   56 
   57 #include <uvm/uvm.h>
   58 #include <uvm/uvm_extern.h>
   59 
   60 #include <fs/smbfs/smbfs.h>
   61 #include <fs/smbfs/smbfs_node.h>
   62 #include <fs/smbfs/smbfs_subr.h>
   63 
   64 #define SMBFS_NOHASH(smp, hval) (&(smp)->sm_hash[(hval) & (smp)->sm_hashlen])
   65 #define smbfs_hash_lock(smp)    lockmgr(&smp->sm_hashlock, LK_EXCLUSIVE, NULL)
   66 #define smbfs_hash_unlock(smp)  lockmgr(&smp->sm_hashlock, LK_RELEASE, NULL)
   67 
   68 MALLOC_DEFINE(M_SMBNODENAME, "SMBFS nname", "SMBFS node name");
   69 
   70 extern int (**smbfs_vnodeop_p) __P((void *));
   71 extern int prtactive;
   72 
   73 static struct genfs_ops smbfs_genfsops = {
   74         NULL,
   75         NULL,
   76         genfs_compat_gop_write,
   77 };
   78 
   79 struct pool smbfs_node_pool;
   80 
   81 static inline char *
   82 smbfs_name_alloc(const u_char *name, int nmlen)
   83 {
   84         u_char *cp;
   85 
   86         cp = malloc(nmlen, M_SMBNODENAME, M_WAITOK);
   87         memcpy(cp, name, nmlen);
   88 
   89         return cp;
   90 }
   91 
   92 static inline void
   93 smbfs_name_free(u_char *name)
   94 {
   95         free(name, M_SMBNODENAME);
   96 }
   97 
   98 static int
   99 smbfs_node_alloc(struct mount *mp, struct vnode *dvp,
  100         const char *name, int nmlen, struct smbfattr *fap, struct vnode **vpp)
  101 {
  102         struct smbmount *smp = VFSTOSMBFS(mp);
  103         struct smbnode_hashhead *nhpp;
  104         struct smbnode *np, *np2, *dnp;
  105         struct vnode *vp;
  106         u_long hashval;
  107         int error;
  108 
  109         /* do not allow allocating root vnode twice */
  110         KASSERT(dvp != NULL || smp->sm_root == NULL);
  111         /* do not call with dot */
  112         KASSERT(nmlen != 1 || name[0] != '.');
  113 
  114         if (nmlen == 2 && memcmp(name, "..", 2) == 0) {
  115                 if (dvp == NULL)
  116                         return EINVAL;
  117                 vp = VTOSMB(dvp)->n_parent->n_vnode;
  118                 if ((error = vget(vp, LK_EXCLUSIVE | LK_RETRY)) == 0)
  119                         *vpp = vp;
  120                 return (error);
  121         }
  122 
  123         dnp = dvp ? VTOSMB(dvp) : NULL;
  124 #ifdef DIAGNOSTIC
  125         if (dnp == NULL && dvp != NULL)
  126                 panic("smbfs_node_alloc: dead parent vnode %p", dvp);
  127 #endif
  128         hashval = smbfs_hash(name, nmlen);
  129 retry:
  130         smbfs_hash_lock(smp);
  131 loop:
  132         nhpp = SMBFS_NOHASH(smp, hashval);
  133         LIST_FOREACH(np, nhpp, n_hash) {
  134                 if (np->n_parent != dnp
  135                     || np->n_nmlen != nmlen
  136                     || memcmp(name, np->n_name, nmlen) != 0)
  137                         continue;
  138                 vp = SMBTOV(np);
  139                 simple_lock(&(vp)->v_interlock);
  140                 smbfs_hash_unlock(smp);
  141                 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK) != 0)
  142                         goto retry;
  143                 *vpp = vp;
  144                 return (0);
  145         }
  146         smbfs_hash_unlock(smp);
  147         /*
  148          * If we don't have node attributes, then it is an explicit lookup
  149          * for an existing vnode.
  150          */
  151         if (fap == NULL)
  152                 return ENOENT;
  153 
  154         np = pool_get(&smbfs_node_pool, PR_WAITOK);
  155         memset(np, 0, sizeof(*np));
  156 
  157         error = getnewvnode(VT_SMBFS, mp, smbfs_vnodeop_p, &vp);
  158         if (error) {
  159                 pool_put(&smbfs_node_pool, np);
  160                 return error;
  161         }
  162         vp->v_type = fap->fa_attr & SMB_FA_DIR ? VDIR : VREG;
  163         vp->v_data = np;
  164         np->n_vnode = vp;
  165         np->n_mount = VFSTOSMBFS(mp);
  166         np->n_nmlen = nmlen;
  167         np->n_name = smbfs_name_alloc(name, nmlen);
  168         np->n_ino = fap->fa_ino;
  169         np->n_size = fap->fa_size;
  170 
  171         /* new file vnode has to have a parent */
  172         KASSERT(vp->v_type != VREG || dvp != NULL);
  173 
  174         if (dvp) {
  175                 np->n_parent = dnp;
  176                 if (/*vp->v_type == VDIR &&*/ (dvp->v_flag & VROOT) == 0) {
  177                         vref(dvp);
  178                         np->n_flag |= NREFPARENT;
  179                 }
  180         }
  181 
  182         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
  183 
  184         smbfs_hash_lock(smp);
  185         /*
  186          * Check if the vnode wasn't added while we were in getnewvnode/
  187          * malloc.
  188          */
  189         LIST_FOREACH(np2, nhpp, n_hash) {
  190                 if (np2->n_parent != dnp
  191                     || np2->n_nmlen != nmlen
  192                     || memcmp(name, np2->n_name, nmlen) != 0)
  193                         continue;
  194                 vput(vp); /* XXX ungetnewvnode/free! */
  195                 goto loop;
  196         }
  197 
  198         /* Not on hash list, add it now */
  199         LIST_INSERT_HEAD(nhpp, np, n_hash);
  200         smbfs_hash_unlock(smp);
  201 
  202         genfs_node_init(vp, &smbfs_genfsops);
  203         uvm_vnp_setsize(vp, np->n_size);
  204         *vpp = vp;
  205         return 0;
  206 }
  207 
  208 int
  209 smbfs_nget(struct mount *mp, struct vnode *dvp, const char *name, int nmlen,
  210         struct smbfattr *fap, struct vnode **vpp)
  211 {
  212         struct vnode *vp;
  213         int error;
  214 
  215         error = smbfs_node_alloc(mp, dvp, name, nmlen, fap, &vp);
  216         if (error)
  217                 return error;
  218         if (fap)
  219                 smbfs_attr_cacheenter(vp, fap);
  220         *vpp = vp;
  221         return 0;
  222 }
  223 
  224 /*
  225  * Free smbnode, and give vnode back to system
  226  */
  227 int
  228 smbfs_reclaim(v)                     
  229      void *v;
  230 {
  231         struct vop_reclaim_args /* {
  232                 struct vnode *a_vp;
  233                 struct thread *a_p;
  234         } */ *ap = v;
  235         struct vnode *vp = ap->a_vp;
  236         struct vnode *dvp;
  237         struct smbnode *np = VTOSMB(vp);
  238         struct smbmount *smp = VTOSMBFS(vp);
  239         
  240         if (prtactive && vp->v_usecount != 0)
  241                 vprint("smbfs_reclaim(): pushing active", vp);
  242 
  243         SMBVDEBUG("%.*s,%d\n", (int) np->n_nmlen, np->n_name, vp->v_usecount);
  244 
  245         KASSERT((np->n_flag & NOPEN) == 0);
  246 
  247         smbfs_hash_lock(smp);
  248 
  249         dvp = (np->n_parent && (np->n_flag & NREFPARENT)) ?
  250             np->n_parent->n_vnode : NULL;
  251 
  252         LIST_REMOVE(np, n_hash);
  253 
  254         cache_purge(vp);
  255         if (smp->sm_root == np) {
  256                 SMBVDEBUG("root vnode\n");
  257                 smp->sm_root = NULL;
  258         }
  259         vp->v_data = NULL;
  260         smbfs_hash_unlock(smp);
  261         if (np->n_name)
  262                 smbfs_name_free(np->n_name);
  263         pool_put(&smbfs_node_pool, np);
  264         if (dvp)
  265                 vrele(dvp);
  266         return 0;
  267 }
  268 
  269 int
  270 smbfs_inactive(v)
  271      void *v;
  272 {
  273         struct vop_inactive_args /* {
  274                 struct vnode *a_vp;
  275                 struct thread *a_td;
  276         } */ *ap = v;
  277         struct proc *p = ap->a_p;
  278         struct ucred *cred = p->p_ucred;
  279         struct vnode *vp = ap->a_vp;
  280         struct smbnode *np = VTOSMB(vp);
  281         struct smb_cred scred;
  282 
  283         if (prtactive && vp->v_usecount != 0)
  284                 vprint("smbfs_inactive(): pushing active", vp);
  285 
  286         SMBVDEBUG("%.*s: %d\n", (int) np->n_nmlen, np->n_name, vp->v_usecount);
  287         if ((np->n_flag & NOPEN) != 0) {
  288                 struct smb_share *ssp = np->n_mount->sm_share;
  289 
  290                 smbfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
  291                 smb_makescred(&scred, p, cred);
  292 
  293                 if (vp->v_type == VDIR && np->n_dirseq) {
  294                         smbfs_findclose(np->n_dirseq, &scred);
  295                         np->n_dirseq = NULL;
  296                 }
  297 
  298                 if (vp->v_type != VDIR
  299                     || SMB_CAPS(SSTOVC(ssp)) & SMB_CAP_NT_SMBS)
  300                         smbfs_smb_close(ssp, np->n_fid, &np->n_mtime, &scred);
  301 
  302                 np->n_flag &= ~NOPEN;
  303                 smbfs_attr_cacheremove(vp);
  304         }
  305         VOP_UNLOCK(vp, 0);
  306         return (0);
  307 }
  308 /*
  309  * routines to maintain vnode attributes cache
  310  * smbfs_attr_cacheenter: unpack np.i to vattr structure
  311  */
  312 void
  313 smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap)
  314 {
  315         struct smbnode *np = VTOSMB(vp);
  316         int s;
  317 
  318         if (vp->v_type == VREG) {
  319                 if (np->n_size != fap->fa_size) {
  320                         np->n_size = fap->fa_size;
  321                         uvm_vnp_setsize(vp, np->n_size);
  322                 }
  323         } else if (vp->v_type == VDIR) {
  324                 np->n_size = 16384;             /* should be a better way ... */
  325         } else
  326                 return;
  327 
  328         np->n_mtime = fap->fa_mtime;
  329         np->n_dosattr = fap->fa_attr;
  330 
  331         s = splclock();
  332         np->n_attrage = mono_time.tv_sec;
  333         splx(s);
  334 }
  335 
  336 int
  337 smbfs_attr_cachelookup(struct vnode *vp, struct vattr *va)
  338 {
  339         struct smbnode *np = VTOSMB(vp);
  340         struct smbmount *smp = VTOSMBFS(vp);
  341         int s;
  342         time_t diff;
  343 
  344         s = splclock();
  345         diff = mono_time.tv_sec - np->n_attrage;
  346         splx(s);
  347         if (diff > SMBFS_ATTRTIMO)      /* XXX should be configurable */
  348                 return ENOENT;
  349 
  350         va->va_type = vp->v_type;               /* vnode type (for create) */
  351         if (vp->v_type == VREG) {
  352                 va->va_mode = smp->sm_args.file_mode;   /* files access mode and type */
  353         } else if (vp->v_type == VDIR) {
  354                 va->va_mode = smp->sm_args.dir_mode;    /* files access mode and type */
  355         } else
  356                 return EINVAL;
  357         va->va_size = np->n_size;
  358         va->va_nlink = 1;               /* number of references to file */
  359         va->va_uid = smp->sm_args.uid;  /* owner user id */
  360         va->va_gid = smp->sm_args.gid;  /* owner group id */
  361         va->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
  362         va->va_fileid = np->n_ino;      /* file id */
  363         if (va->va_fileid == 0)
  364                 va->va_fileid = 2;
  365         va->va_blocksize = SSTOVC(smp->sm_share)->vc_txmax;
  366         va->va_mtime = np->n_mtime;
  367         va->va_atime = va->va_ctime = va->va_mtime;     /* time file changed */
  368         va->va_gen = VNOVAL;            /* generation number of file */
  369         va->va_flags = 0;               /* flags defined for file */
  370         va->va_rdev = VNOVAL;           /* device the special file represents */
  371         va->va_bytes = va->va_size;     /* bytes of disk space held by file */
  372         va->va_filerev = 0;             /* file modification number */
  373         va->va_vaflags = 0;             /* operations flags */
  374         return 0;
  375 }

Cache object: 893f95f4b453a08a36b134695e981119


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