1 /* $NetBSD: ops_cachefs.c,v 1.1.1.2 2009/03/20 20:26:49 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2009 Erez Zadok 5 * Copyright (c) 1990 Jan-Simon Pendry 6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgment: 23 * This product includes software developed by the University of 24 * California, Berkeley and its contributors. 25 * 4. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 * 41 * 42 * File: am-utils/amd/ops_cachefs.c 43 * 44 */ 45 46 /* 47 * Caching filesystem (Solaris 2.x) 48 */ 49 50 #ifdef HAVE_CONFIG_H 51 # include <config.h> 52 #endif /* HAVE_CONFIG_H */ 53 #include <am_defs.h> 54 #include <amd.h> 55 56 /* forward declarations */ 57 static char *cachefs_match(am_opts *fo); 58 static int cachefs_init(mntfs *mf); 59 static int cachefs_mount(am_node *am, mntfs *mf); 60 static int cachefs_umount(am_node *am, mntfs *mf); 61 62 63 /* 64 * Ops structure 65 */ 66 am_ops cachefs_ops = 67 { 68 "cachefs", 69 cachefs_match, 70 cachefs_init, 71 cachefs_mount, 72 cachefs_umount, 73 amfs_error_lookup_child, 74 amfs_error_mount_child, 75 amfs_error_readdir, 76 0, /* cachefs_readlink */ 77 0, /* cachefs_mounted */ 78 0, /* cachefs_umounted */ 79 amfs_generic_find_srvr, 80 0, /* cachefs_get_wchan */ 81 FS_MKMNT | FS_NOTIMEOUT | FS_UBACKGROUND | FS_AMQINFO, /* nfs_fs_flags */ 82 #ifdef HAVE_FS_AUTOFS 83 AUTOFS_CACHEFS_FS_FLAGS, 84 #endif /* HAVE_FS_AUTOFS */ 85 }; 86 87 88 /* 89 * Check that f/s has all needed fields. 90 * Returns: matched string if found, NULL otherwise. 91 */ 92 static char * 93 cachefs_match(am_opts *fo) 94 { 95 /* sanity check */ 96 if (!fo->opt_rfs || !fo->opt_fs || !fo->opt_cachedir) { 97 plog(XLOG_USER, "cachefs: must specify cachedir, rfs, and fs"); 98 return NULL; 99 } 100 101 dlog("CACHEFS: using cache directory \"%s\"", fo->opt_cachedir); 102 103 /* determine magic cookie to put in mtab */ 104 return strdup(fo->opt_cachedir); 105 } 106 107 108 /* 109 * Initialize. 110 * Returns: 0 if OK, non-zero (errno) if failed. 111 */ 112 static int 113 cachefs_init(mntfs *mf) 114 { 115 /* 116 * Save cache directory name 117 */ 118 if (!mf->mf_private) { 119 mf->mf_private = (voidp) strdup(mf->mf_fo->opt_cachedir); 120 mf->mf_prfree = (void (*)(voidp)) free; 121 } 122 123 return 0; 124 } 125 126 127 /* 128 * mntpt is the mount point ($fs) [XXX: was 'dir'] 129 * backdir is the mounted pathname ($rfs) [XXX: was 'fs_name'] 130 * cachedir is the cache directory ($cachedir) 131 */ 132 static int 133 mount_cachefs(char *mntdir, char *backdir, char *cachedir, 134 char *opts, int on_autofs) 135 { 136 cachefs_args_t ca; 137 mntent_t mnt; 138 int flags; 139 char *cp; 140 MTYPE_TYPE type = MOUNT_TYPE_CACHEFS; /* F/S mount type */ 141 142 memset((voidp) &ca, 0, sizeof(ca)); /* Paranoid */ 143 144 /* 145 * Fill in the mount structure 146 */ 147 memset((voidp) &mnt, 0, sizeof(mnt)); 148 mnt.mnt_dir = mntdir; 149 mnt.mnt_fsname = backdir; 150 mnt.mnt_type = MNTTAB_TYPE_CACHEFS; 151 mnt.mnt_opts = opts; 152 153 flags = compute_mount_flags(&mnt); 154 #ifdef HAVE_FS_AUTOFS 155 if (on_autofs) 156 flags |= autofs_compute_mount_flags(&mnt); 157 #endif /* HAVE_FS_AUTOFS */ 158 159 /* Fill in cachefs mount arguments */ 160 161 /* 162 * XXX: Caveats 163 * (1) cache directory is NOT checked for sanity beforehand, nor is it 164 * purged. Maybe it should be purged first? 165 * (2) cache directory is NOT locked. Should we? 166 */ 167 168 /* mount flags */ 169 ca.cfs_options.opt_flags = CFS_WRITE_AROUND | CFS_ACCESS_BACKFS; 170 /* cache population size */ 171 ca.cfs_options.opt_popsize = DEF_POP_SIZE; /* default: 64K */ 172 /* filegrp size */ 173 ca.cfs_options.opt_fgsize = DEF_FILEGRP_SIZE; /* default: 256 */ 174 175 /* CFS ID for file system (must be unique) */ 176 ca.cfs_fsid = cachedir; 177 178 /* CFS fscdir name */ 179 memset(ca.cfs_cacheid, 0, sizeof(ca.cfs_cacheid)); 180 /* 181 * Append cacheid and mountpoint. 182 * sizeof(cfs_cacheid) should be C_MAX_MOUNT_FSCDIRNAME as per 183 * <sys/fs/cachefs_fs.h> (checked on Solaris 8). 184 */ 185 xsnprintf(ca.cfs_cacheid, sizeof(ca.cfs_cacheid), 186 "%s:%s", ca.cfs_fsid, mntdir); 187 /* convert '/' to '_' (Solaris does that...) */ 188 cp = ca.cfs_cacheid; 189 while ((cp = strpbrk(cp, "/")) != NULL) 190 *cp = '_'; 191 192 /* path for this cache dir */ 193 ca.cfs_cachedir = cachedir; 194 195 /* back filesystem dir */ 196 ca.cfs_backfs = backdir; 197 198 /* same as nfs values (XXX: need to handle these options) */ 199 ca.cfs_acregmin = 0; 200 ca.cfs_acregmax = 0; 201 ca.cfs_acdirmin = 0; 202 ca.cfs_acdirmax = 0; 203 204 /* 205 * Call generic mount routine 206 */ 207 return mount_fs(&mnt, flags, (caddr_t) &ca, 0, type, 0, NULL, mnttab_file_name, on_autofs); 208 } 209 210 211 static int 212 cachefs_mount(am_node *am, mntfs *mf) 213 { 214 int on_autofs = mf->mf_flags & MFF_ON_AUTOFS; 215 int error; 216 217 error = mount_cachefs(mf->mf_mount, 218 mf->mf_fo->opt_rfs, 219 mf->mf_fo->opt_cachedir, 220 mf->mf_mopts, 221 on_autofs); 222 if (error) { 223 errno = error; 224 /* according to Solaris, if errno==ESRCH, "options to not match" */ 225 if (error == ESRCH) 226 plog(XLOG_ERROR, "mount_cachefs: options to no match: %m"); 227 else 228 plog(XLOG_ERROR, "mount_cachefs: %m"); 229 return error; 230 } 231 232 return 0; 233 } 234 235 236 static int 237 cachefs_umount(am_node *am, mntfs *mf) 238 { 239 int unmount_flags = (mf->mf_flags & MFF_ON_AUTOFS) ? AMU_UMOUNT_AUTOFS : 0; 240 int error; 241 242 error = UMOUNT_FS(mf->mf_mount, mnttab_file_name, unmount_flags); 243 244 /* 245 * In the case of cachefs, we must fsck the cache directory. Otherwise, 246 * it will remain inconsistent, and the next cachefs mount will fail 247 * with the error "no space left on device" (ENOSPC). 248 * 249 * XXX: this is hacky! use fork/exec/wait instead... 250 */ 251 if (!error) { 252 char *cachedir = NULL; 253 char cmd[128]; 254 255 cachedir = (char *) mf->mf_private; 256 plog(XLOG_INFO, "running fsck on cache directory \"%s\"", cachedir); 257 xsnprintf(cmd, sizeof(cmd), "fsck -F cachefs %s", cachedir); 258 system(cmd); 259 } 260 261 return error; 262 } 263