1 /*- 2 * Copyright (c) 2016 Tomohiro Kusumi <kusumi.tomohiro@gmail.com> 3 * Copyright (c) 2016 The DragonFly Project 4 * Copyright (c) 2014 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Edward Tomasz Napierala under sponsorship 8 * from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/stat.h> 36 37 #include "autofs.h" 38 #include "autofs_mount.h" 39 40 static int autofs_statfs(struct mount *mp, struct statfs *sbp, 41 struct ucred *cred); 42 43 static struct objcache_malloc_args autofs_request_args = { 44 sizeof(struct autofs_request), M_AUTOFS, 45 }; 46 static struct objcache_malloc_args autofs_node_args = { 47 sizeof(struct autofs_node), M_AUTOFS, 48 }; 49 50 static int 51 autofs_init(struct vfsconf *vfsp) 52 { 53 KASSERT(autofs_softc == NULL, 54 ("softc %p, should be NULL", autofs_softc)); 55 56 autofs_softc = kmalloc(sizeof(*autofs_softc), M_AUTOFS, 57 M_WAITOK | M_ZERO); 58 59 autofs_request_objcache = objcache_create("autofs_request", 0, 0, 60 NULL, NULL, NULL, 61 objcache_malloc_alloc_zero, objcache_malloc_free, 62 &autofs_request_args); 63 64 autofs_node_objcache = objcache_create("autofs_node", 0, 0, 65 NULL, NULL, NULL, 66 objcache_malloc_alloc_zero, objcache_malloc_free, 67 &autofs_node_args); 68 69 TAILQ_INIT(&autofs_softc->sc_requests); 70 cv_init(&autofs_softc->sc_cv, "autofscv"); 71 mtx_init(&autofs_softc->sc_lock, "autofssclk"); 72 autofs_softc->sc_dev_opened = false; 73 74 autofs_softc->sc_cdev = make_dev(&autofs_ops, 0, UID_ROOT, GID_OPERATOR, 75 0640, "autofs"); 76 if (autofs_softc->sc_cdev == NULL) { 77 AUTOFS_WARN("failed to create device node"); 78 objcache_destroy(autofs_request_objcache); 79 objcache_destroy(autofs_node_objcache); 80 kfree(autofs_softc, M_AUTOFS); 81 return (ENODEV); 82 } 83 autofs_softc->sc_cdev->si_drv1 = autofs_softc; 84 85 return (0); 86 } 87 88 static int 89 autofs_uninit(struct vfsconf *vfsp) 90 { 91 mtx_lock_ex_quick(&autofs_softc->sc_lock); 92 if (autofs_softc->sc_dev_opened) { 93 mtx_unlock_ex(&autofs_softc->sc_lock); 94 return (EBUSY); 95 } 96 97 if (autofs_softc->sc_cdev != NULL) 98 destroy_dev(autofs_softc->sc_cdev); 99 100 objcache_destroy(autofs_request_objcache); 101 objcache_destroy(autofs_node_objcache); 102 103 mtx_unlock_ex(&autofs_softc->sc_lock); 104 105 kfree(autofs_softc, M_AUTOFS); /* race with open */ 106 autofs_softc = NULL; 107 108 return (0); 109 } 110 111 static int 112 autofs_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred) 113 { 114 struct autofs_mount_info info; 115 struct autofs_mount *amp; 116 struct statfs *sbp = &mp->mnt_stat; 117 int error; 118 119 if (mp->mnt_flag & MNT_UPDATE) { 120 autofs_flush(VFSTOAUTOFS(mp)); 121 return (0); 122 } 123 124 error = copyin(data, &info, sizeof(info)); 125 if (error) 126 return (error); 127 128 /* 129 * Copy-in ->f_mntfromname string. 130 */ 131 memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname)); 132 error = copyinstr(info.from, sbp->f_mntfromname, 133 sizeof(sbp->f_mntfromname), NULL); 134 if (error) 135 return (error); 136 /* 137 * Copy-in ->f_mntonname string. 138 */ 139 memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname)); 140 error = copyinstr(mntpt, sbp->f_mntonname, sizeof(sbp->f_mntonname), 141 NULL); 142 if (error) 143 return (error); 144 145 /* 146 * Allocate the autofs mount. 147 */ 148 amp = kmalloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO); 149 mp->mnt_data = (qaddr_t)amp; 150 amp->am_mp = mp; 151 strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from)); 152 strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on)); 153 154 /* 155 * Copy-in master_options string. 156 */ 157 error = copyinstr(info.master_options, amp->am_options, 158 sizeof(amp->am_options), NULL); 159 if (error) 160 goto fail; 161 /* 162 * Copy-in master_prefix string. 163 */ 164 error = copyinstr(info.master_prefix, amp->am_prefix, 165 sizeof(amp->am_prefix), NULL); 166 if (error) 167 goto fail; 168 169 /* 170 * Initialize the autofs mount. 171 */ 172 mtx_init(&->am_lock, "autofsmnlk"); 173 amp->am_last_ino = AUTOFS_ROOTINO; 174 175 mtx_lock_ex_quick(&->am_lock); 176 error = autofs_node_new(NULL, amp, ".", -1, &->am_root); 177 mtx_unlock_ex(&->am_lock); 178 KKASSERT(error == 0); 179 KKASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO); 180 181 vfs_getnewfsid(mp); 182 vfs_add_vnodeops(mp, &autofs_vnode_vops, &mp->mnt_vn_norm_ops); 183 184 autofs_statfs(mp, sbp, cred); 185 186 return (0); 187 188 fail: 189 kfree(amp, M_AUTOFS); 190 return (error); 191 } 192 193 static int 194 autofs_unmount(struct mount *mp, int mntflags) 195 { 196 struct autofs_mount *amp = VFSTOAUTOFS(mp); 197 int error, flags; 198 199 flags = 0; 200 if (mntflags & MNT_FORCE) 201 flags |= FORCECLOSE; 202 error = vflush(mp, 0, flags); 203 if (error) { 204 AUTOFS_WARN("vflush failed with error %d", error); 205 return (error); 206 } 207 208 /* 209 * All vnodes are gone, and new one will not appear - so, 210 * no new triggerings. 211 */ 212 for (;;) { 213 struct autofs_request *ar; 214 int dummy; 215 bool found; 216 217 found = false; 218 mtx_lock_ex_quick(&autofs_softc->sc_lock); 219 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 220 if (ar->ar_mount != amp) 221 continue; 222 ar->ar_error = ENXIO; 223 ar->ar_done = true; 224 ar->ar_in_progress = false; 225 found = true; 226 } 227 if (found == false) { 228 mtx_unlock_ex(&autofs_softc->sc_lock); 229 break; 230 } 231 232 cv_broadcast(&autofs_softc->sc_cv); 233 mtx_unlock_ex(&autofs_softc->sc_lock); 234 235 tsleep(&dummy, 0, "autofs_umount", hz); 236 } 237 238 mtx_lock_ex_quick(&->am_lock); 239 while (!RB_EMPTY(&->am_root->an_children)) { 240 struct autofs_node *anp; 241 /* 242 * Force delete all nodes when more than one level of 243 * directories are created via indirect map. Autofs doesn't 244 * support rmdir(2), thus this is the only way to get out. 245 */ 246 anp = RB_MIN(autofs_node_tree, &->am_root->an_children); 247 while (!RB_EMPTY(&anp->an_children)) 248 anp = RB_MIN(autofs_node_tree, &anp->an_children); 249 autofs_node_delete(anp); 250 } 251 autofs_node_delete(amp->am_root); 252 mp->mnt_data = NULL; 253 mtx_unlock_ex(&->am_lock); 254 255 mtx_uninit(&->am_lock); 256 257 kfree(amp, M_AUTOFS); 258 259 return (0); 260 } 261 262 static int 263 autofs_root(struct mount *mp, struct vnode **vpp) 264 { 265 struct autofs_mount *amp = VFSTOAUTOFS(mp); 266 int error; 267 268 KASSERT(amp->am_root, ("no root node")); 269 270 error = autofs_node_vn(amp->am_root, mp, LK_EXCLUSIVE, vpp); 271 if (error == 0) { 272 struct vnode *vp = *vpp; 273 vp->v_flag |= VROOT; 274 KKASSERT(vp->v_type == VDIR); 275 } 276 277 return (error); 278 } 279 280 static int 281 autofs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 282 { 283 sbp->f_bsize = S_BLKSIZE; 284 sbp->f_iosize = 0; 285 sbp->f_blocks = 0; 286 sbp->f_bfree = 0; 287 sbp->f_bavail = 0; 288 sbp->f_files = 0; 289 sbp->f_ffree = 0; 290 291 return (0); 292 } 293 294 static int 295 autofs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 296 { 297 sbp->f_bsize = S_BLKSIZE; 298 sbp->f_frsize = 0; 299 sbp->f_blocks = 0; 300 sbp->f_bfree = 0; 301 sbp->f_bavail = 0; 302 sbp->f_files = 0; 303 sbp->f_ffree = 0; 304 305 return (0); 306 } 307 308 static struct vfsops autofs_vfsops = { 309 .vfs_mount = autofs_mount, 310 .vfs_unmount = autofs_unmount, 311 .vfs_root = autofs_root, 312 .vfs_statfs = autofs_statfs, 313 .vfs_statvfs = autofs_statvfs, 314 .vfs_init = autofs_init, 315 .vfs_uninit = autofs_uninit, 316 }; 317 318 VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_MPSAFE); 319 MODULE_VERSION(autofs, 1); 320