1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 #pragma ident   "%Z%%M% %I%     %E% SMI"
  26 
  27 #include <sys/param.h>
  28 #include <sys/types.h>
  29 #include <sys/systm.h>
  30 #include <sys/cred.h>
  31 #include <sys/proc.h>
  32 #include <sys/user.h>
  33 #include <sys/vfs.h>
  34 #include <sys/vnode.h>
  35 #include <sys/pathname.h>
  36 #include <sys/uio.h>
  37 #include <sys/tiuser.h>
  38 #include <sys/sysmacros.h>
  39 #include <sys/kmem.h>
  40 #include <sys/mount.h>
  41 #include <sys/ioctl.h>
  42 #include <sys/statvfs.h>
  43 #include <sys/errno.h>
  44 #include <sys/debug.h>
  45 #include <sys/cmn_err.h>
  46 #include <sys/utsname.h>
  47 #include <sys/bootconf.h>
  48 #include <sys/modctl.h>
  49 
  50 #include <sys/fs/cachefs_fs.h>
  51 
  52 /*ARGSUSED*/
  53 static int
  54 c_nop_init_cached_object(fscache_t *fscp, cnode_t *cp, vattr_t *vap,
  55     cred_t *cr)
  56 {
  57         int error;
  58         cachefs_metadata_t *mdp = &cp->c_metadata;
  59 
  60         ASSERT(cr != NULL);
  61         ASSERT(MUTEX_HELD(&cp->c_statelock));
  62 
  63         /* NFSv4 always sets strict consistency */
  64         ASSERT(CFS_ISFS_BACKFS_NFSV4(fscp) == 0);
  65 
  66         /* if attributes not passed in then get them */
  67         if (vap == NULL) {
  68                 /* if not connected then cannot get attrs */
  69                 if ((fscp->fs_cdconnected != CFS_CD_CONNECTED) ||
  70                     (fscp->fs_backvfsp == NULL))
  71                         return (ETIMEDOUT);
  72 
  73                 /* get backvp if necessary */
  74                 if (cp->c_backvp == NULL) {
  75                         error = cachefs_getbackvp(fscp, cp);
  76                         if (error)
  77                                 return (error);
  78                 }
  79 
  80                 /* get the attributes */
  81                 cp->c_attr.va_mask = AT_ALL;
  82                 ASSERT(cp->c_backvp != NULL);
  83                 error = VOP_GETATTR(cp->c_backvp, &cp->c_attr, 0, cr, NULL);
  84                 if (error)
  85                         return (error);
  86         } else {
  87                 /* copy passed in attributes into the cnode */
  88                 cp->c_attr = *vap;
  89         }
  90 
  91         cp->c_size = cp->c_attr.va_size;
  92         mdp->md_consttype = CFS_FS_CONST_NOCONST;
  93         cp->c_flags |= CN_UPDATED;
  94         return (0);
  95 }
  96 
  97 /*ARGSUSED*/
  98 static int
  99 c_nop_check_cached_object(struct fscache *fscp, struct cnode *cp,
 100         int verify_what, cred_t *cr)
 101 {
 102         struct vattr attrs;
 103         int fail = 0, backhit = 0;
 104         int error = 0;
 105         cachefs_metadata_t *mdp = &cp->c_metadata;
 106 
 107         ASSERT(cr);
 108         ASSERT(MUTEX_HELD(&cp->c_statelock));
 109 
 110         /* nothing to do if not connected */
 111         if ((fscp->fs_cdconnected != CFS_CD_CONNECTED) ||
 112             (fscp->fs_backvfsp == NULL))
 113                 goto out;
 114 
 115         /* done if do not have to check */
 116         if (((verify_what & C_BACK_CHECK) == 0) &&
 117             ((mdp->md_flags & MD_NEEDATTRS) == 0))
 118                 goto out;
 119 
 120         /* get backvp if necessary */
 121         if (cp->c_backvp == NULL) {
 122                 error = cachefs_getbackvp(fscp, cp);
 123                 if (error)
 124                         goto out;
 125         }
 126 
 127         /* get the file attributes from the back fs */
 128         attrs.va_mask = AT_ALL;
 129         error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
 130         backhit = 1;
 131         if (error)
 132                 goto out;
 133 
 134         cp->c_attr = attrs;
 135         if (attrs.va_size > cp->c_size)
 136                 cp->c_size = attrs.va_size;
 137         mdp->md_flags &= ~MD_NEEDATTRS;
 138         cachefs_cnode_setlocalstats(cp);
 139         cp->c_flags |= CN_UPDATED;
 140 
 141 out:
 142         if (backhit != 0) {
 143                 if (fail != 0)
 144                         fscp->fs_stats.st_fails++;
 145                 else
 146                         fscp->fs_stats.st_passes++;
 147         }
 148 
 149         return (error);
 150 }
 151 
 152 static void
 153 c_nop_modify_cached_object(struct fscache *fscp, struct cnode *cp, cred_t *cr)
 154 {
 155         struct vattr attrs;
 156         int     error;
 157         nlink_t nlink;
 158         cachefs_metadata_t *mdp = &cp->c_metadata;
 159 
 160         ASSERT(MUTEX_HELD(&cp->c_statelock));
 161         ASSERT(fscp->fs_cdconnected == CFS_CD_CONNECTED);
 162         ASSERT(fscp->fs_backvfsp);
 163 
 164         fscp->fs_stats.st_modifies++;
 165 
 166         /* from now on, make sure we're using the server's idea of time */
 167         mdp->md_flags &= ~(MD_LOCALCTIME | MD_LOCALMTIME);
 168         mdp->md_flags |= MD_NEEDATTRS;
 169 
 170         /* if in write-around mode, make sure file is nocached */
 171         if (CFS_ISFS_WRITE_AROUND(fscp)) {
 172                 if ((cp->c_flags & CN_NOCACHE) == 0)
 173                         cachefs_nocache(cp);
 174         }
 175 
 176         /* get the new attributes so we don't wait forever to get them */
 177         if (cp->c_backvp == NULL) {
 178                 error = cachefs_getbackvp(fscp, cp);
 179                 if (error)
 180                         return;
 181         }
 182         attrs.va_mask = AT_ALL;
 183         error = VOP_GETATTR(cp->c_backvp, &attrs, 0, cr, NULL);
 184         if (error)
 185                 return;
 186         nlink = cp->c_attr.va_nlink;
 187         cp->c_attr = attrs;
 188         cp->c_attr.va_nlink = nlink;
 189         if ((attrs.va_size > cp->c_size) || !vn_has_cached_data(CTOV(cp)))
 190                 cp->c_size = attrs.va_size;
 191         mdp->md_flags &= ~MD_NEEDATTRS;
 192         cachefs_cnode_setlocalstats(cp);
 193         cp->c_flags |= CN_UPDATED;
 194 }
 195 
 196 /*ARGSUSED*/
 197 static void
 198 c_nop_invalidate_cached_object(struct fscache *fscp, struct cnode *cp,
 199         cred_t *cr)
 200 {
 201         cachefs_metadata_t *mdp = &cp->c_metadata;
 202 
 203         ASSERT(MUTEX_HELD(&cp->c_statelock));
 204         mdp->md_flags |= MD_NEEDATTRS;
 205         cp->c_flags |= CN_UPDATED;
 206 }
 207 
 208 /*ARGSUSED*/
 209 static void
 210 c_nop_convert_cached_object(struct fscache *fscp, struct cnode *cp,
 211         cred_t *cr)
 212 {
 213         cachefs_metadata_t *mdp = &cp->c_metadata;
 214         mdp->md_flags |= MD_NEEDATTRS;
 215         mdp->md_consttype = CFS_FS_CONST_NOCONST;
 216         cp->c_flags |= CN_UPDATED;
 217 }
 218 
 219 struct cachefsops nopcfsops = {
 220         c_nop_init_cached_object,
 221         c_nop_check_cached_object,
 222         c_nop_modify_cached_object,
 223         c_nop_invalidate_cached_object,
 224         c_nop_convert_cached_object
 225 };