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