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 strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from)); 151 strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on)); 152 153 /* 154 * Copy-in master_options string. 155 */ 156 error = copyinstr(info.master_options, amp->am_options, 157 sizeof(amp->am_options), NULL); 158 if (error) 159 goto fail; 160 /* 161 * Copy-in master_prefix string. 162 */ 163 error = copyinstr(info.master_prefix, amp->am_prefix, 164 sizeof(amp->am_prefix), NULL); 165 if (error) 166 goto fail; 167 168 /* 169 * Initialize the autofs mount. 170 */ 171 mtx_init(&->am_lock, "autofsmnlk"); 172 amp->am_last_ino = AUTOFS_ROOTINO; 173 174 mtx_lock_ex_quick(&->am_lock); 175 error = autofs_node_new(NULL, amp, ".", -1, &->am_root); 176 mtx_unlock_ex(&->am_lock); 177 KKASSERT(error == 0); 178 KKASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO); 179 180 vfs_getnewfsid(mp); 181 vfs_add_vnodeops(mp, &autofs_vnode_vops, &mp->mnt_vn_norm_ops); 182 183 VFS_STATFS(mp, &mp->mnt_stat, cred); 184 185 return (0); 186 187 fail: 188 kfree(amp, M_AUTOFS); 189 return (error); 190 } 191 192 static int 193 autofs_unmount(struct mount *mp, int mntflags) 194 { 195 struct autofs_mount *amp = VFSTOAUTOFS(mp); 196 int error, flags; 197 198 flags = 0; 199 if (mntflags & MNT_FORCE) 200 flags |= FORCECLOSE; 201 error = vflush(mp, 0, flags); 202 if (error) { 203 AUTOFS_WARN("vflush failed with error %d", error); 204 return (error); 205 } 206 207 /* 208 * All vnodes are gone, and new one will not appear - so, 209 * no new triggerings. 210 */ 211 for (;;) { 212 struct autofs_request *ar; 213 int dummy; 214 bool found; 215 216 found = false; 217 mtx_lock_ex_quick(&autofs_softc->sc_lock); 218 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 219 if (ar->ar_mount != amp) 220 continue; 221 ar->ar_error = ENXIO; 222 ar->ar_done = true; 223 ar->ar_in_progress = false; 224 found = true; 225 } 226 if (found == false) { 227 mtx_unlock_ex(&autofs_softc->sc_lock); 228 break; 229 } 230 231 cv_broadcast(&autofs_softc->sc_cv); 232 mtx_unlock_ex(&autofs_softc->sc_lock); 233 234 tsleep(&dummy, 0, "autofs_umount", hz); 235 } 236 237 mtx_lock_ex_quick(&->am_lock); 238 while (!RB_EMPTY(&->am_root->an_children)) { 239 struct autofs_node *anp; 240 /* 241 * Force delete all nodes when more than one level of 242 * directories are created via indirect map. Autofs doesn't 243 * support rmdir(2), thus this is the only way to get out. 244 */ 245 anp = RB_MIN(autofs_node_tree, &->am_root->an_children); 246 while (!RB_EMPTY(&anp->an_children)) 247 anp = RB_MIN(autofs_node_tree, &anp->an_children); 248 autofs_node_delete(anp); 249 } 250 autofs_node_delete(amp->am_root); 251 mp->mnt_data = NULL; 252 mtx_unlock_ex(&->am_lock); 253 254 mtx_uninit(&->am_lock); 255 256 kfree(amp, M_AUTOFS); 257 258 return (0); 259 } 260 261 static int 262 autofs_root(struct mount *mp, struct vnode **vpp) 263 { 264 struct autofs_mount *amp = VFSTOAUTOFS(mp); 265 int error; 266 267 KASSERT(amp->am_root, ("no root node")); 268 269 error = autofs_node_vn(amp->am_root, mp, LK_EXCLUSIVE, vpp); 270 if (error == 0) { 271 struct vnode *vp = *vpp; 272 vp->v_flag |= VROOT; 273 KKASSERT(vp->v_type == VDIR); 274 } 275 276 return (error); 277 } 278 279 static int 280 autofs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 281 { 282 sbp->f_bsize = S_BLKSIZE; 283 sbp->f_iosize = 0; 284 sbp->f_blocks = 0; 285 sbp->f_bfree = 0; 286 sbp->f_bavail = 0; 287 sbp->f_files = 0; 288 sbp->f_ffree = 0; 289 290 return (0); 291 } 292 293 static int 294 autofs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 295 { 296 sbp->f_bsize = S_BLKSIZE; 297 sbp->f_frsize = 0; 298 sbp->f_blocks = 0; 299 sbp->f_bfree = 0; 300 sbp->f_bavail = 0; 301 sbp->f_files = 0; 302 sbp->f_ffree = 0; 303 304 return (0); 305 } 306 307 static struct vfsops autofs_vfsops = { 308 .vfs_mount = autofs_mount, 309 .vfs_unmount = autofs_unmount, 310 .vfs_root = autofs_root, 311 .vfs_statfs = autofs_statfs, 312 .vfs_statvfs = autofs_statvfs, 313 .vfs_init = autofs_init, 314 .vfs_uninit = autofs_uninit, 315 }; 316 317 VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_MPSAFE); 318 MODULE_VERSION(autofs, 1); 319