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, 62 objcache_malloc_free, 63 &autofs_request_args); 64 65 autofs_node_objcache = objcache_create("autofs_node", 0, 0, 66 NULL, NULL, NULL, 67 objcache_malloc_alloc_zero, 68 objcache_malloc_free, 69 &autofs_node_args); 70 71 TAILQ_INIT(&autofs_softc->sc_requests); 72 cv_init(&autofs_softc->sc_cv, "autofscv"); 73 mtx_init(&autofs_softc->sc_lock, "autofssclk"); 74 autofs_softc->sc_dev_opened = false; 75 76 autofs_softc->sc_cdev = make_dev(&autofs_ops, 0, UID_ROOT, 77 GID_OPERATOR, 0640, "autofs"); 78 if (autofs_softc->sc_cdev == NULL) { 79 AUTOFS_WARN("failed to create device node"); 80 objcache_destroy(autofs_request_objcache); 81 objcache_destroy(autofs_node_objcache); 82 kfree(autofs_softc, M_AUTOFS); 83 84 return (ENODEV); 85 } 86 autofs_softc->sc_cdev->si_drv1 = autofs_softc; 87 88 return (0); 89 } 90 91 static int 92 autofs_uninit(struct vfsconf *vfsp) 93 { 94 mtx_lock_ex_quick(&autofs_softc->sc_lock); 95 if (autofs_softc->sc_dev_opened) { 96 mtx_unlock_ex(&autofs_softc->sc_lock); 97 return (EBUSY); 98 } 99 100 if (autofs_softc->sc_cdev != NULL) 101 destroy_dev(autofs_softc->sc_cdev); 102 103 objcache_destroy(autofs_request_objcache); 104 objcache_destroy(autofs_node_objcache); 105 106 mtx_unlock_ex(&autofs_softc->sc_lock); 107 108 kfree(autofs_softc, M_AUTOFS); /* race with open */ 109 autofs_softc = NULL; 110 111 return (0); 112 } 113 114 static int 115 autofs_mount(struct mount *mp, char *mntpt, caddr_t data, struct ucred *cred) 116 { 117 struct autofs_mount_info info; 118 struct autofs_mount *amp; 119 struct statfs *sbp = &mp->mnt_stat; 120 int error; 121 122 if (mp->mnt_flag & MNT_UPDATE) { 123 autofs_flush(VFSTOAUTOFS(mp)); 124 return (0); 125 } 126 127 error = copyin(data, &info, sizeof(info)); 128 if (error) 129 return (error); 130 131 /* 132 * Copy-in ->f_mntfromname string. 133 */ 134 memset(sbp->f_mntfromname, 0, sizeof(sbp->f_mntfromname)); 135 error = copyinstr(info.from, sbp->f_mntfromname, 136 sizeof(sbp->f_mntfromname), NULL); 137 if (error) 138 return (error); 139 /* 140 * Copy-in ->f_mntonname string. 141 */ 142 memset(sbp->f_mntonname, 0, sizeof(sbp->f_mntonname)); 143 error = copyinstr(mntpt, sbp->f_mntonname, 144 sizeof(sbp->f_mntonname), NULL); 145 if (error) 146 return (error); 147 148 /* 149 * Allocate the autofs mount. 150 */ 151 amp = kmalloc(sizeof(*amp), M_AUTOFS, M_WAITOK | M_ZERO); 152 mp->mnt_data = (qaddr_t)amp; 153 amp->am_mp = mp; 154 strlcpy(amp->am_from, sbp->f_mntfromname, sizeof(amp->am_from)); 155 strlcpy(amp->am_on, sbp->f_mntonname, sizeof(amp->am_on)); 156 157 /* 158 * Copy-in master_options string. 159 */ 160 error = copyinstr(info.master_options, amp->am_options, 161 sizeof(amp->am_options), NULL); 162 if (error) 163 goto fail; 164 /* 165 * Copy-in master_prefix string. 166 */ 167 error = copyinstr(info.master_prefix, amp->am_prefix, 168 sizeof(amp->am_prefix), NULL); 169 if (error) 170 goto fail; 171 172 /* 173 * Initialize the autofs mount. 174 */ 175 mtx_init(&->am_lock, "autofsmnlk"); 176 amp->am_last_ino = AUTOFS_ROOTINO; 177 178 vfs_getnewfsid(mp); 179 vfs_add_vnodeops(mp, &autofs_vnode_vops, &mp->mnt_vn_norm_ops); 180 181 mtx_lock_ex_quick(&->am_lock); 182 error = autofs_node_new(NULL, amp, ".", -1, &->am_root); 183 mtx_unlock_ex(&->am_lock); 184 KKASSERT(error == 0); 185 KKASSERT(amp->am_root->an_ino == AUTOFS_ROOTINO); 186 187 autofs_statfs(mp, sbp, cred); 188 189 return (0); 190 191 fail: 192 kfree(amp, M_AUTOFS); 193 return (error); 194 } 195 196 static int 197 autofs_unmount(struct mount *mp, int mntflags) 198 { 199 struct autofs_mount *amp = VFSTOAUTOFS(mp); 200 int error, flags; 201 202 flags = 0; 203 if (mntflags & MNT_FORCE) 204 flags |= FORCECLOSE; 205 error = vflush(mp, 0, flags); 206 if (error) { 207 AUTOFS_WARN("vflush failed with error %d", error); 208 return (error); 209 } 210 211 /* 212 * All vnodes are gone, and new one will not appear - so, 213 * no new triggerings. 214 */ 215 for (;;) { 216 struct autofs_request *ar; 217 int dummy; 218 bool found; 219 220 found = false; 221 mtx_lock_ex_quick(&autofs_softc->sc_lock); 222 TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) { 223 if (ar->ar_mount != amp) 224 continue; 225 ar->ar_error = ENXIO; 226 ar->ar_done = true; 227 ar->ar_in_progress = false; 228 found = true; 229 } 230 if (found == false) { 231 mtx_unlock_ex(&autofs_softc->sc_lock); 232 break; 233 } 234 235 cv_broadcast(&autofs_softc->sc_cv); 236 mtx_unlock_ex(&autofs_softc->sc_lock); 237 238 tsleep(&dummy, 0, "autofs_umount", hz); 239 } 240 241 mtx_lock_ex_quick(&->am_lock); 242 while (!RB_EMPTY(&->am_root->an_children)) { 243 struct autofs_node *anp; 244 /* 245 * Force delete all nodes when more than one level of 246 * directories are created via indirect map. Autofs doesn't 247 * support rmdir(2), thus this is the only way to get out. 248 */ 249 anp = RB_MIN(autofs_node_tree, &->am_root->an_children); 250 while (!RB_EMPTY(&anp->an_children)) 251 anp = RB_MIN(autofs_node_tree, &anp->an_children); 252 autofs_node_delete(anp); 253 } 254 autofs_node_delete(amp->am_root); 255 mp->mnt_data = NULL; 256 mtx_unlock_ex(&->am_lock); 257 258 mtx_uninit(&->am_lock); 259 260 kfree(amp, M_AUTOFS); 261 262 return (0); 263 } 264 265 static int 266 autofs_root(struct mount *mp, struct vnode **vpp) 267 { 268 struct autofs_mount *amp = VFSTOAUTOFS(mp); 269 int error; 270 271 if (amp->am_root == NULL) { 272 AUTOFS_FATAL("called without root node %p", mp); 273 print_backtrace(-1); 274 *vpp = NULL; 275 error = EINVAL; 276 } else { 277 error = autofs_node_vn(amp->am_root, mp, LK_EXCLUSIVE, vpp); 278 (*vpp)->v_flag |= VROOT; 279 KKASSERT((*vpp)->v_type == VDIR); 280 } 281 282 return (error); 283 } 284 285 static int 286 autofs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 287 { 288 sbp->f_bsize = S_BLKSIZE; 289 sbp->f_iosize = 0; 290 sbp->f_blocks = 0; 291 sbp->f_bfree = 0; 292 sbp->f_bavail = 0; 293 sbp->f_files = 0; 294 sbp->f_ffree = 0; 295 296 return (0); 297 } 298 299 static int 300 autofs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 301 { 302 sbp->f_bsize = S_BLKSIZE; 303 sbp->f_frsize = 0; 304 sbp->f_blocks = 0; 305 sbp->f_bfree = 0; 306 sbp->f_bavail = 0; 307 sbp->f_files = 0; 308 sbp->f_ffree = 0; 309 310 return (0); 311 } 312 313 static struct vfsops autofs_vfsops = { 314 .vfs_mount = autofs_mount, 315 .vfs_unmount = autofs_unmount, 316 .vfs_root = autofs_root, 317 .vfs_statfs = autofs_statfs, 318 .vfs_statvfs = autofs_statvfs, 319 .vfs_init = autofs_init, 320 .vfs_uninit = autofs_uninit, 321 }; 322 323 VFS_SET(autofs_vfsops, autofs, VFCF_SYNTHETIC | VFCF_MPSAFE); 324 MODULE_VERSION(autofs, 1); 325