author | Casper H.S. Dik <Casper.Dik@Sun.COM> |
Wed, 28 Apr 2010 10:01:37 +0200 | |
changeset 12273 | 63678502e95e |
parent 11185 | f0c31008e395 |
child 12633 | 9f2cda0ed938 |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* CDDL HEADER START |
|
3 |
* |
|
4 |
* The contents of this file are subject to the terms of the |
|
1488 | 5 |
* Common Development and Distribution License (the "License"). |
6 |
* You may not use this file except in compliance with the License. |
|
0 | 7 |
* |
8 |
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
|
9 |
* or http://www.opensolaris.org/os/licensing. |
|
10 |
* See the License for the specific language governing permissions |
|
11 |
* and limitations under the License. |
|
12 |
* |
|
13 |
* When distributing Covered Code, include this CDDL HEADER in each |
|
14 |
* file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
|
15 |
* If applicable, add the following below this CDDL HEADER, with the |
|
16 |
* fields enclosed by brackets "[]" replaced with your own identifying |
|
17 |
* information: Portions Copyright [yyyy] [name of copyright owner] |
|
18 |
* |
|
19 |
* CDDL HEADER END |
|
20 |
*/ |
|
21 |
/* |
|
12273
63678502e95e
PSARC 2009/377 In-kernel pfexec implementation.
Casper H.S. Dik <Casper.Dik@Sun.COM>
parents:
11185
diff
changeset
|
22 |
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 23 |
*/ |
24 |
||
25 |
#include <sys/param.h> |
|
26 |
#include <sys/errno.h> |
|
27 |
#include <sys/proc.h> |
|
28 |
#include <sys/disp.h> |
|
29 |
#include <sys/vfs.h> |
|
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
2516
diff
changeset
|
30 |
#include <sys/vfs_opreg.h> |
0 | 31 |
#include <sys/vnode.h> |
32 |
#include <sys/uio.h> |
|
33 |
#include <sys/kmem.h> |
|
34 |
#include <sys/cred.h> |
|
35 |
#include <sys/statvfs.h> |
|
36 |
#include <sys/mount.h> |
|
37 |
#include <sys/tiuser.h> |
|
38 |
#include <sys/cmn_err.h> |
|
39 |
#include <sys/debug.h> |
|
40 |
#include <sys/systm.h> |
|
41 |
#include <sys/sysmacros.h> |
|
42 |
#include <sys/pathname.h> |
|
43 |
#include <rpc/types.h> |
|
44 |
#include <rpc/auth.h> |
|
45 |
#include <rpc/clnt.h> |
|
46 |
#include <fs/fs_subr.h> |
|
47 |
#include <sys/fs/autofs.h> |
|
48 |
#include <sys/modctl.h> |
|
49 |
#include <sys/mntent.h> |
|
50 |
#include <sys/policy.h> |
|
51 |
#include <sys/zone.h> |
|
52 |
||
53 |
static int autofs_init(int, char *); |
|
54 |
||
55 |
static major_t autofs_major; |
|
56 |
static minor_t autofs_minor; |
|
57 |
||
4092
c859d126a342
6513455 automounter is not responding to interrupts correctly
evanl
parents:
3898
diff
changeset
|
58 |
kmutex_t autofs_minor_lock; |
0 | 59 |
zone_key_t autofs_key; |
60 |
||
61 |
static mntopts_t auto_mntopts; |
|
62 |
||
63 |
/* |
|
64 |
* The AUTOFS system call. |
|
65 |
*/ |
|
66 |
static struct sysent autofssysent = { |
|
67 |
2, |
|
68 |
SE_32RVAL1 | SE_ARGC | SE_NOUNLOAD, |
|
69 |
autofssys |
|
70 |
}; |
|
71 |
||
72 |
static struct modlsys modlsys = { |
|
73 |
&mod_syscallops, |
|
74 |
"AUTOFS syscall", |
|
75 |
&autofssysent |
|
76 |
}; |
|
77 |
||
78 |
#ifdef _SYSCALL32_IMPL |
|
79 |
static struct modlsys modlsys32 = { |
|
80 |
&mod_syscallops32, |
|
81 |
"AUTOFS syscall (32-bit)", |
|
82 |
&autofssysent |
|
83 |
}; |
|
84 |
#endif /* _SYSCALL32_IMPL */ |
|
85 |
||
86 |
static vfsdef_t vfw = { |
|
87 |
VFSDEF_VERSION, |
|
88 |
"autofs", |
|
89 |
autofs_init, |
|
1488 | 90 |
VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_STATS, |
0 | 91 |
&auto_mntopts |
92 |
}; |
|
93 |
||
94 |
/* |
|
95 |
* Module linkage information for the kernel. |
|
96 |
*/ |
|
97 |
static struct modlfs modlfs = { |
|
98 |
&mod_fsops, "filesystem for autofs", &vfw |
|
99 |
}; |
|
100 |
||
101 |
static struct modlinkage modlinkage = { |
|
102 |
MODREV_1, |
|
2516
391407c3e041
6452979 Single panic "assertion failed: fngp->fng_fnnode_count == 1" on Sun-Blade-1000 BrandZ snv_43r2
evanl
parents:
2170
diff
changeset
|
103 |
&modlfs, |
0 | 104 |
&modlsys, |
105 |
#ifdef _SYSCALL32_IMPL |
|
106 |
&modlsys32, |
|
107 |
#endif |
|
108 |
NULL |
|
109 |
}; |
|
110 |
||
111 |
/* |
|
112 |
* There are not enough stubs for rpcmod so we must force load it |
|
113 |
*/ |
|
114 |
char _depends_on[] = "strmod/rpcmod misc/rpcsec fs/mntfs"; |
|
115 |
||
116 |
/* |
|
117 |
* This is the module initialization routine. |
|
118 |
*/ |
|
119 |
int |
|
120 |
_init(void) |
|
121 |
{ |
|
122 |
return (mod_install(&modlinkage)); |
|
123 |
} |
|
124 |
||
125 |
int |
|
126 |
_fini(void) |
|
127 |
{ |
|
128 |
/* |
|
129 |
* Don't allow the autofs module to be unloaded for now. |
|
130 |
*/ |
|
131 |
return (EBUSY); |
|
132 |
} |
|
133 |
||
134 |
int |
|
135 |
_info(struct modinfo *modinfop) |
|
136 |
{ |
|
137 |
return (mod_info(&modlinkage, modinfop)); |
|
138 |
} |
|
139 |
||
140 |
static int autofs_fstype; |
|
141 |
||
142 |
/* |
|
143 |
* autofs VFS operations |
|
144 |
*/ |
|
145 |
static int auto_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *); |
|
146 |
static int auto_unmount(vfs_t *, int, cred_t *); |
|
147 |
static int auto_root(vfs_t *, vnode_t **); |
|
148 |
static int auto_statvfs(vfs_t *, struct statvfs64 *); |
|
149 |
||
150 |
/* |
|
151 |
* Auto Mount options table |
|
152 |
*/ |
|
153 |
||
154 |
static char *direct_cancel[] = { MNTOPT_INDIRECT, NULL }; |
|
155 |
static char *indirect_cancel[] = { MNTOPT_DIRECT, NULL }; |
|
156 |
static char *browse_cancel[] = { MNTOPT_NOBROWSE, NULL }; |
|
157 |
static char *nobrowse_cancel[] = { MNTOPT_BROWSE, NULL }; |
|
158 |
||
159 |
static mntopt_t mntopts[] = { |
|
160 |
/* |
|
161 |
* option name cancel options default arg flags |
|
162 |
*/ |
|
163 |
{ MNTOPT_DIRECT, direct_cancel, NULL, 0, |
|
164 |
NULL }, |
|
165 |
{ MNTOPT_INDIRECT, indirect_cancel, NULL, 0, |
|
166 |
NULL }, |
|
167 |
{ MNTOPT_IGNORE, NULL, NULL, |
|
168 |
MO_DEFAULT|MO_TAG, NULL }, |
|
169 |
{ "nest", NULL, NULL, MO_TAG, |
|
170 |
NULL }, |
|
171 |
{ MNTOPT_BROWSE, browse_cancel, NULL, MO_TAG, |
|
172 |
NULL }, |
|
173 |
{ MNTOPT_NOBROWSE, nobrowse_cancel, NULL, MO_TAG, |
|
174 |
NULL }, |
|
175 |
{ MNTOPT_RESTRICT, NULL, NULL, MO_TAG, |
|
176 |
NULL }, |
|
177 |
}; |
|
178 |
||
179 |
static mntopts_t auto_mntopts = { |
|
180 |
sizeof (mntopts) / sizeof (mntopt_t), |
|
181 |
mntopts |
|
182 |
}; |
|
183 |
||
184 |
/*ARGSUSED*/ |
|
185 |
static void |
|
186 |
autofs_zone_destructor(zoneid_t zoneid, void *arg) |
|
187 |
{ |
|
188 |
struct autofs_globals *fngp = arg; |
|
189 |
vnode_t *vp; |
|
190 |
||
191 |
if (fngp == NULL) |
|
192 |
return; |
|
193 |
ASSERT(fngp->fng_fnnode_count == 1); |
|
194 |
ASSERT(fngp->fng_unmount_threads == 0); |
|
12273
63678502e95e
PSARC 2009/377 In-kernel pfexec implementation.
Casper H.S. Dik <Casper.Dik@Sun.COM>
parents:
11185
diff
changeset
|
195 |
|
63678502e95e
PSARC 2009/377 In-kernel pfexec implementation.
Casper H.S. Dik <Casper.Dik@Sun.COM>
parents:
11185
diff
changeset
|
196 |
if (fngp->fng_autofs_daemon_dh != NULL) |
63678502e95e
PSARC 2009/377 In-kernel pfexec implementation.
Casper H.S. Dik <Casper.Dik@Sun.COM>
parents:
11185
diff
changeset
|
197 |
door_ki_rele(fngp->fng_autofs_daemon_dh); |
0 | 198 |
/* |
199 |
* vn_alloc() initialized the rootnode with a count of 1; we need to |
|
200 |
* make this 0 to placate auto_freefnnode(). |
|
201 |
*/ |
|
202 |
vp = fntovn(fngp->fng_rootfnnodep); |
|
203 |
ASSERT(vp->v_count == 1); |
|
204 |
vp->v_count--; |
|
205 |
auto_freefnnode(fngp->fng_rootfnnodep); |
|
206 |
mutex_destroy(&fngp->fng_unmount_threads_lock); |
|
207 |
kmem_free(fngp, sizeof (*fngp)); |
|
208 |
} |
|
209 |
||
210 |
/* |
|
211 |
* rootfnnodep is allocated here. Its sole purpose is to provide |
|
212 |
* read/write locking for top level fnnodes. This object is |
|
213 |
* persistent and will not be deallocated until the zone is destroyed. |
|
214 |
* |
|
215 |
* The current zone is implied as the zone of interest, since we will be |
|
216 |
* calling zthread_create() which must be called from the correct zone. |
|
217 |
*/ |
|
2170 | 218 |
struct autofs_globals * |
0 | 219 |
autofs_zone_init(void) |
220 |
{ |
|
221 |
char rootname[sizeof ("root_fnnode_zone_") + ZONEID_WIDTH]; |
|
222 |
struct autofs_globals *fngp; |
|
223 |
zoneid_t zoneid = getzoneid(); |
|
224 |
||
225 |
fngp = kmem_zalloc(sizeof (*fngp), KM_SLEEP); |
|
226 |
(void) snprintf(rootname, sizeof (rootname), "root_fnnode_zone_%d", |
|
227 |
zoneid); |
|
228 |
fngp->fng_rootfnnodep = auto_makefnnode(VNON, NULL, rootname, CRED(), |
|
229 |
fngp); |
|
230 |
/* |
|
231 |
* Don't need to hold fng_rootfnnodep as it's never really used for |
|
232 |
* anything. |
|
233 |
*/ |
|
234 |
fngp->fng_fnnode_count = 1; |
|
235 |
fngp->fng_printed_not_running_msg = 0; |
|
236 |
fngp->fng_zoneid = zoneid; |
|
237 |
mutex_init(&fngp->fng_unmount_threads_lock, NULL, MUTEX_DEFAULT, |
|
238 |
NULL); |
|
239 |
fngp->fng_unmount_threads = 0; |
|
240 |
||
2170 | 241 |
mutex_init(&fngp->fng_autofs_daemon_lock, NULL, MUTEX_DEFAULT, NULL); |
242 |
||
0 | 243 |
/* |
244 |
* Start the unmounter thread for this zone. |
|
245 |
*/ |
|
246 |
(void) zthread_create(NULL, 0, auto_do_unmount, fngp, 0, minclsyspri); |
|
247 |
return (fngp); |
|
248 |
} |
|
249 |
||
250 |
int |
|
251 |
autofs_init(int fstype, char *name) |
|
252 |
{ |
|
253 |
static const fs_operation_def_t auto_vfsops_template[] = { |
|
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
2516
diff
changeset
|
254 |
VFSNAME_MOUNT, { .vfs_mount = auto_mount }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
2516
diff
changeset
|
255 |
VFSNAME_UNMOUNT, { .vfs_unmount = auto_unmount }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
2516
diff
changeset
|
256 |
VFSNAME_ROOT, { .vfs_root = auto_root }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
2516
diff
changeset
|
257 |
VFSNAME_STATVFS, { .vfs_statvfs = auto_statvfs }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
2516
diff
changeset
|
258 |
NULL, NULL |
0 | 259 |
}; |
260 |
int error; |
|
261 |
||
262 |
autofs_fstype = fstype; |
|
263 |
ASSERT(autofs_fstype != 0); |
|
264 |
/* |
|
265 |
* Associate VFS ops vector with this fstype |
|
266 |
*/ |
|
267 |
error = vfs_setfsops(fstype, auto_vfsops_template, NULL); |
|
268 |
if (error != 0) { |
|
269 |
cmn_err(CE_WARN, "autofs_init: bad vfs ops template"); |
|
270 |
return (error); |
|
271 |
} |
|
272 |
||
273 |
error = vn_make_ops(name, auto_vnodeops_template, &auto_vnodeops); |
|
274 |
if (error != 0) { |
|
275 |
(void) vfs_freevfsops_by_type(fstype); |
|
276 |
cmn_err(CE_WARN, "autofs_init: bad vnode ops template"); |
|
277 |
return (error); |
|
278 |
} |
|
279 |
||
280 |
mutex_init(&autofs_minor_lock, NULL, MUTEX_DEFAULT, NULL); |
|
281 |
/* |
|
282 |
* Assign unique major number for all autofs mounts |
|
283 |
*/ |
|
284 |
if ((autofs_major = getudev()) == (major_t)-1) { |
|
285 |
cmn_err(CE_WARN, |
|
286 |
"autofs: autofs_init: can't get unique device number"); |
|
287 |
mutex_destroy(&autofs_minor_lock); |
|
288 |
return (1); |
|
289 |
} |
|
290 |
||
291 |
/* |
|
292 |
* We'd like to be able to provide a constructor here, but we can't |
|
293 |
* since it wants to zthread_create(), something it can't do in a ZSD |
|
294 |
* constructor. |
|
295 |
*/ |
|
296 |
zone_key_create(&autofs_key, NULL, NULL, autofs_zone_destructor); |
|
297 |
||
298 |
return (0); |
|
299 |
} |
|
300 |
||
301 |
static char *restropts[] = { |
|
302 |
RESTRICTED_MNTOPTS |
|
303 |
}; |
|
304 |
||
305 |
/* |
|
306 |
* This routine adds those options to the option string `buf' which are |
|
307 |
* forced by secpolicy_fs_mount. If the automatic "security" options |
|
308 |
* are set, the option string gets them added if they aren't already |
|
309 |
* there. We search the string with "strstr" and make sure that |
|
310 |
* the string we find is bracketed with <start|",">MNTOPT<","|"\0"> |
|
311 |
* |
|
312 |
* This is one half of the option inheritence algorithm which |
|
313 |
* implements the "restrict" option. The other half is implemented |
|
314 |
* in automountd; it takes its cue from the options we add here. |
|
315 |
*/ |
|
316 |
static int |
|
317 |
autofs_restrict_opts(struct vfs *vfsp, char *buf, size_t maxlen, size_t *curlen) |
|
318 |
{ |
|
319 |
int i; |
|
320 |
char *p; |
|
321 |
size_t len = *curlen - 1; |
|
322 |
||
323 |
/* Unrestricted */ |
|
324 |
if (!vfs_optionisset(vfsp, restropts[0], NULL)) |
|
325 |
return (0); |
|
326 |
||
327 |
for (i = 0; i < sizeof (restropts)/sizeof (restropts[0]); i++) { |
|
328 |
size_t olen = strlen(restropts[i]); |
|
329 |
||
330 |
/* Add "restrict" always and the others insofar set */ |
|
331 |
if ((i == 0 || vfs_optionisset(vfsp, restropts[i], NULL)) && |
|
332 |
((p = strstr(buf, restropts[i])) == NULL || |
|
333 |
!((p == buf || p[-1] == ',') && |
|
334 |
(p[olen] == '\0' || p[olen] == ',')))) { |
|
335 |
||
336 |
if (len + olen + 1 > maxlen) |
|
337 |
return (-1); |
|
338 |
||
339 |
if (*buf != '\0') |
|
340 |
buf[len++] = ','; |
|
341 |
(void) strcpy(&buf[len], restropts[i]); |
|
342 |
len += olen; |
|
343 |
} |
|
344 |
} |
|
345 |
*curlen = len + 1; |
|
346 |
return (0); |
|
347 |
} |
|
348 |
||
349 |
/* ARGSUSED */ |
|
350 |
static int |
|
351 |
auto_mount(vfs_t *vfsp, vnode_t *vp, struct mounta *uap, cred_t *cr) |
|
352 |
{ |
|
353 |
int error; |
|
354 |
size_t len = 0; |
|
2170 | 355 |
autofs_args args; |
0 | 356 |
fninfo_t *fnip = NULL; |
357 |
vnode_t *rootvp = NULL; |
|
358 |
fnnode_t *rootfnp = NULL; |
|
359 |
char *data = uap->dataptr; |
|
360 |
char datalen = uap->datalen; |
|
361 |
dev_t autofs_dev; |
|
2170 | 362 |
char strbuff[MAXPATHLEN + 1]; |
11185
f0c31008e395
6887924 PP_ISKAS needs to be defined in terms of VN_ISKAS for vnodes
Sean McEnroe <Sean.McEnroe@Sun.COM>
parents:
4092
diff
changeset
|
363 |
vnode_t *kkvp; |
0 | 364 |
struct autofs_globals *fngp; |
365 |
zone_t *zone = curproc->p_zone; |
|
366 |
||
367 |
AUTOFS_DPRINT((4, "auto_mount: vfs %p vp %p\n", (void *)vfsp, |
|
368 |
(void *)vp)); |
|
369 |
||
370 |
if ((error = secpolicy_fs_mount(cr, vp, vfsp)) != 0) |
|
371 |
return (EPERM); |
|
372 |
||
373 |
if (zone == global_zone) { |
|
374 |
zone_t *mntzone; |
|
375 |
||
376 |
mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); |
|
377 |
ASSERT(mntzone != NULL); |
|
378 |
zone_rele(mntzone); |
|
379 |
if (mntzone != zone) { |
|
380 |
return (EBUSY); |
|
381 |
} |
|
382 |
} |
|
383 |
||
384 |
/* |
|
385 |
* Stop the mount from going any further if the zone is going away. |
|
386 |
*/ |
|
387 |
if (zone_status_get(zone) >= ZONE_IS_SHUTTING_DOWN) |
|
388 |
return (EBUSY); |
|
389 |
||
390 |
/* |
|
391 |
* We need a lock to serialize this; minor_lock is as good as any. |
|
392 |
*/ |
|
393 |
mutex_enter(&autofs_minor_lock); |
|
394 |
if ((fngp = zone_getspecific(autofs_key, zone)) == NULL) { |
|
395 |
fngp = autofs_zone_init(); |
|
396 |
(void) zone_setspecific(autofs_key, zone, fngp); |
|
397 |
} |
|
398 |
mutex_exit(&autofs_minor_lock); |
|
399 |
ASSERT(fngp != NULL); |
|
400 |
||
401 |
/* |
|
402 |
* Get arguments |
|
403 |
*/ |
|
404 |
if (uap->flags & MS_SYSSPACE) { |
|
405 |
if (datalen != sizeof (args)) |
|
406 |
return (EINVAL); |
|
407 |
error = kcopy(data, &args, sizeof (args)); |
|
408 |
} else { |
|
409 |
if (get_udatamodel() == DATAMODEL_NATIVE) { |
|
410 |
if (datalen != sizeof (args)) |
|
411 |
return (EINVAL); |
|
412 |
error = copyin(data, &args, sizeof (args)); |
|
413 |
} else { |
|
414 |
struct autofs_args32 args32; |
|
415 |
||
416 |
if (datalen != sizeof (args32)) |
|
417 |
return (EINVAL); |
|
418 |
error = copyin(data, &args32, sizeof (args32)); |
|
419 |
||
420 |
args.addr.maxlen = args32.addr.maxlen; |
|
421 |
args.addr.len = args32.addr.len; |
|
422 |
args.addr.buf = (char *)(uintptr_t)args32.addr.buf; |
|
423 |
args.path = (char *)(uintptr_t)args32.path; |
|
424 |
args.opts = (char *)(uintptr_t)args32.opts; |
|
425 |
args.map = (char *)(uintptr_t)args32.map; |
|
426 |
args.subdir = (char *)(uintptr_t)args32.subdir; |
|
427 |
args.key = (char *)(uintptr_t)args32.key; |
|
428 |
args.mount_to = args32.mount_to; |
|
429 |
args.rpc_to = args32.rpc_to; |
|
430 |
args.direct = args32.direct; |
|
431 |
} |
|
432 |
} |
|
433 |
if (error) |
|
434 |
return (EFAULT); |
|
435 |
||
436 |
/* |
|
437 |
* For a remount, only update mount information |
|
438 |
* i.e. default mount options, map name, etc. |
|
439 |
*/ |
|
440 |
if (uap->flags & MS_REMOUNT) { |
|
441 |
fnip = vfstofni(vfsp); |
|
442 |
if (fnip == NULL) |
|
443 |
return (EINVAL); |
|
444 |
||
445 |
if (args.direct == 1) |
|
446 |
fnip->fi_flags |= MF_DIRECT; |
|
447 |
else |
|
448 |
fnip->fi_flags &= ~MF_DIRECT; |
|
449 |
fnip->fi_mount_to = args.mount_to; |
|
450 |
fnip->fi_rpc_to = args.rpc_to; |
|
451 |
||
452 |
/* |
|
453 |
* Get default options |
|
454 |
*/ |
|
455 |
if (uap->flags & MS_SYSSPACE) |
|
456 |
error = copystr(args.opts, strbuff, sizeof (strbuff), |
|
457 |
&len); |
|
458 |
else |
|
459 |
error = copyinstr(args.opts, strbuff, sizeof (strbuff), |
|
460 |
&len); |
|
461 |
if (error) |
|
462 |
return (EFAULT); |
|
463 |
||
464 |
if (autofs_restrict_opts(vfsp, strbuff, sizeof (strbuff), &len) |
|
465 |
!= 0) { |
|
466 |
return (EFAULT); |
|
467 |
} |
|
468 |
||
469 |
kmem_free(fnip->fi_opts, fnip->fi_optslen); |
|
470 |
fnip->fi_opts = kmem_alloc(len, KM_SLEEP); |
|
471 |
fnip->fi_optslen = (int)len; |
|
472 |
bcopy(strbuff, fnip->fi_opts, len); |
|
473 |
||
474 |
/* |
|
475 |
* Get context/map name |
|
476 |
*/ |
|
477 |
if (uap->flags & MS_SYSSPACE) |
|
478 |
error = copystr(args.map, strbuff, sizeof (strbuff), |
|
479 |
&len); |
|
480 |
else |
|
481 |
error = copyinstr(args.map, strbuff, sizeof (strbuff), |
|
482 |
&len); |
|
483 |
if (error) |
|
484 |
return (EFAULT); |
|
485 |
||
486 |
kmem_free(fnip->fi_map, fnip->fi_maplen); |
|
487 |
fnip->fi_map = kmem_alloc(len, KM_SLEEP); |
|
488 |
fnip->fi_maplen = (int)len; |
|
489 |
bcopy(strbuff, fnip->fi_map, len); |
|
490 |
||
491 |
return (0); |
|
492 |
} |
|
493 |
||
494 |
/* |
|
495 |
* Allocate fninfo struct and attach it to vfs |
|
496 |
*/ |
|
497 |
fnip = kmem_zalloc(sizeof (*fnip), KM_SLEEP); |
|
498 |
fnip->fi_mountvfs = vfsp; |
|
499 |
||
500 |
fnip->fi_mount_to = args.mount_to; |
|
501 |
fnip->fi_rpc_to = args.rpc_to; |
|
502 |
fnip->fi_refcnt = 0; |
|
503 |
vfsp->vfs_bsize = AUTOFS_BLOCKSIZE; |
|
504 |
vfsp->vfs_fstype = autofs_fstype; |
|
505 |
||
506 |
/* |
|
507 |
* Assign a unique device id to the mount |
|
508 |
*/ |
|
509 |
mutex_enter(&autofs_minor_lock); |
|
510 |
do { |
|
511 |
autofs_minor = (autofs_minor + 1) & L_MAXMIN32; |
|
512 |
autofs_dev = makedevice(autofs_major, autofs_minor); |
|
513 |
} while (vfs_devismounted(autofs_dev)); |
|
514 |
mutex_exit(&autofs_minor_lock); |
|
515 |
vfsp->vfs_dev = autofs_dev; |
|
516 |
vfs_make_fsid(&vfsp->vfs_fsid, autofs_dev, autofs_fstype); |
|
517 |
vfsp->vfs_data = (void *)fnip; |
|
518 |
vfsp->vfs_bcount = 0; |
|
519 |
||
520 |
/* |
|
521 |
* Get daemon address |
|
522 |
*/ |
|
523 |
fnip->fi_addr.len = args.addr.len; |
|
524 |
fnip->fi_addr.maxlen = fnip->fi_addr.len; |
|
525 |
fnip->fi_addr.buf = kmem_alloc(args.addr.len, KM_SLEEP); |
|
526 |
if (uap->flags & MS_SYSSPACE) |
|
527 |
error = kcopy(args.addr.buf, fnip->fi_addr.buf, args.addr.len); |
|
528 |
else |
|
529 |
error = copyin(args.addr.buf, fnip->fi_addr.buf, args.addr.len); |
|
530 |
if (error) { |
|
531 |
error = EFAULT; |
|
532 |
goto errout; |
|
533 |
} |
|
534 |
||
535 |
fnip->fi_zoneid = getzoneid(); |
|
536 |
/* |
|
537 |
* Get path for mountpoint |
|
538 |
*/ |
|
539 |
if (uap->flags & MS_SYSSPACE) |
|
540 |
error = copystr(args.path, strbuff, sizeof (strbuff), &len); |
|
541 |
else |
|
542 |
error = copyinstr(args.path, strbuff, sizeof (strbuff), &len); |
|
543 |
if (error) { |
|
544 |
error = EFAULT; |
|
545 |
goto errout; |
|
546 |
} |
|
547 |
fnip->fi_path = kmem_alloc(len, KM_SLEEP); |
|
548 |
fnip->fi_pathlen = (int)len; |
|
549 |
bcopy(strbuff, fnip->fi_path, len); |
|
550 |
||
551 |
/* |
|
552 |
* Get default options |
|
553 |
*/ |
|
554 |
if (uap->flags & MS_SYSSPACE) |
|
555 |
error = copystr(args.opts, strbuff, sizeof (strbuff), &len); |
|
556 |
else |
|
557 |
error = copyinstr(args.opts, strbuff, sizeof (strbuff), &len); |
|
558 |
||
559 |
if (error != 0 || |
|
560 |
autofs_restrict_opts(vfsp, strbuff, sizeof (strbuff), &len) != 0) { |
|
561 |
error = EFAULT; |
|
562 |
goto errout; |
|
563 |
} |
|
564 |
fnip->fi_opts = kmem_alloc(len, KM_SLEEP); |
|
565 |
fnip->fi_optslen = (int)len; |
|
566 |
bcopy(strbuff, fnip->fi_opts, len); |
|
567 |
||
568 |
/* |
|
569 |
* Get context/map name |
|
570 |
*/ |
|
571 |
if (uap->flags & MS_SYSSPACE) |
|
572 |
error = copystr(args.map, strbuff, sizeof (strbuff), &len); |
|
573 |
else |
|
574 |
error = copyinstr(args.map, strbuff, sizeof (strbuff), &len); |
|
575 |
if (error) { |
|
576 |
error = EFAULT; |
|
577 |
goto errout; |
|
578 |
} |
|
579 |
fnip->fi_map = kmem_alloc(len, KM_SLEEP); |
|
580 |
fnip->fi_maplen = (int)len; |
|
581 |
bcopy(strbuff, fnip->fi_map, len); |
|
582 |
||
583 |
/* |
|
584 |
* Get subdirectory within map |
|
585 |
*/ |
|
586 |
if (uap->flags & MS_SYSSPACE) |
|
587 |
error = copystr(args.subdir, strbuff, sizeof (strbuff), &len); |
|
588 |
else |
|
589 |
error = copyinstr(args.subdir, strbuff, sizeof (strbuff), &len); |
|
590 |
if (error) { |
|
591 |
error = EFAULT; |
|
592 |
goto errout; |
|
593 |
} |
|
594 |
fnip->fi_subdir = kmem_alloc(len, KM_SLEEP); |
|
595 |
fnip->fi_subdirlen = (int)len; |
|
596 |
bcopy(strbuff, fnip->fi_subdir, len); |
|
597 |
||
598 |
/* |
|
599 |
* Get the key |
|
600 |
*/ |
|
601 |
if (uap->flags & MS_SYSSPACE) |
|
602 |
error = copystr(args.key, strbuff, sizeof (strbuff), &len); |
|
603 |
else |
|
604 |
error = copyinstr(args.key, strbuff, sizeof (strbuff), &len); |
|
605 |
if (error) { |
|
606 |
error = EFAULT; |
|
607 |
goto errout; |
|
608 |
} |
|
609 |
fnip->fi_key = kmem_alloc(len, KM_SLEEP); |
|
610 |
fnip->fi_keylen = (int)len; |
|
611 |
bcopy(strbuff, fnip->fi_key, len); |
|
612 |
||
613 |
/* |
|
614 |
* Is this a direct mount? |
|
615 |
*/ |
|
616 |
if (args.direct == 1) |
|
617 |
fnip->fi_flags |= MF_DIRECT; |
|
618 |
||
619 |
/* |
|
620 |
* Setup netconfig. |
|
621 |
* Can I pass in knconf as mount argument? what |
|
622 |
* happens when the daemon gets restarted? |
|
623 |
*/ |
|
624 |
if ((error = lookupname("/dev/ticotsord", UIO_SYSSPACE, FOLLOW, |
|
11185
f0c31008e395
6887924 PP_ISKAS needs to be defined in terms of VN_ISKAS for vnodes
Sean McEnroe <Sean.McEnroe@Sun.COM>
parents:
4092
diff
changeset
|
625 |
NULLVPP, &kkvp)) != 0) { |
0 | 626 |
cmn_err(CE_WARN, "autofs: lookupname: %d", error); |
627 |
goto errout; |
|
628 |
} |
|
629 |
||
11185
f0c31008e395
6887924 PP_ISKAS needs to be defined in terms of VN_ISKAS for vnodes
Sean McEnroe <Sean.McEnroe@Sun.COM>
parents:
4092
diff
changeset
|
630 |
fnip->fi_knconf.knc_rdev = kkvp->v_rdev; |
0 | 631 |
fnip->fi_knconf.knc_protofmly = NC_LOOPBACK; |
632 |
fnip->fi_knconf.knc_semantics = NC_TPI_COTS_ORD; |
|
11185
f0c31008e395
6887924 PP_ISKAS needs to be defined in terms of VN_ISKAS for vnodes
Sean McEnroe <Sean.McEnroe@Sun.COM>
parents:
4092
diff
changeset
|
633 |
VN_RELE(kkvp); |
0 | 634 |
|
635 |
/* |
|
636 |
* Make the root vnode |
|
637 |
*/ |
|
638 |
rootfnp = auto_makefnnode(VDIR, vfsp, fnip->fi_path, cr, fngp); |
|
639 |
if (rootfnp == NULL) { |
|
640 |
error = ENOMEM; |
|
641 |
goto errout; |
|
642 |
} |
|
643 |
rootvp = fntovn(rootfnp); |
|
644 |
||
645 |
rootvp->v_flag |= VROOT; |
|
646 |
rootfnp->fn_mode = AUTOFS_MODE; |
|
647 |
rootfnp->fn_parent = rootfnp; |
|
648 |
/* account for ".." entry */ |
|
649 |
rootfnp->fn_linkcnt = rootfnp->fn_size = 1; |
|
650 |
fnip->fi_rootvp = rootvp; |
|
651 |
||
652 |
/* |
|
653 |
* Add to list of top level AUTOFS' if it is being mounted by |
|
654 |
* a user level process. |
|
655 |
*/ |
|
656 |
if (!(uap->flags & MS_SYSSPACE)) { |
|
657 |
rw_enter(&fngp->fng_rootfnnodep->fn_rwlock, RW_WRITER); |
|
658 |
rootfnp->fn_parent = fngp->fng_rootfnnodep; |
|
659 |
rootfnp->fn_next = fngp->fng_rootfnnodep->fn_dirents; |
|
660 |
fngp->fng_rootfnnodep->fn_dirents = rootfnp; |
|
661 |
rw_exit(&fngp->fng_rootfnnodep->fn_rwlock); |
|
662 |
} |
|
663 |
||
664 |
AUTOFS_DPRINT((5, "auto_mount: vfs %p root %p fnip %p return %d\n", |
|
665 |
(void *)vfsp, (void *)rootvp, (void *)fnip, error)); |
|
666 |
||
667 |
return (0); |
|
668 |
||
669 |
errout: |
|
670 |
ASSERT(fnip != NULL); |
|
671 |
ASSERT((uap->flags & MS_REMOUNT) == 0); |
|
672 |
||
673 |
if (fnip->fi_addr.buf != NULL) |
|
674 |
kmem_free(fnip->fi_addr.buf, fnip->fi_addr.len); |
|
675 |
if (fnip->fi_path != NULL) |
|
676 |
kmem_free(fnip->fi_path, fnip->fi_pathlen); |
|
677 |
if (fnip->fi_opts != NULL) |
|
678 |
kmem_free(fnip->fi_opts, fnip->fi_optslen); |
|
679 |
if (fnip->fi_map != NULL) |
|
680 |
kmem_free(fnip->fi_map, fnip->fi_maplen); |
|
681 |
if (fnip->fi_subdir != NULL) |
|
682 |
kmem_free(fnip->fi_subdir, fnip->fi_subdirlen); |
|
683 |
if (fnip->fi_key != NULL) |
|
684 |
kmem_free(fnip->fi_key, fnip->fi_keylen); |
|
685 |
kmem_free(fnip, sizeof (*fnip)); |
|
686 |
||
687 |
AUTOFS_DPRINT((5, "auto_mount: vfs %p root %p fnip %p return %d\n", |
|
688 |
(void *)vfsp, (void *)rootvp, (void *)fnip, error)); |
|
689 |
||
690 |
return (error); |
|
691 |
} |
|
692 |
||
693 |
/* ARGSUSED */ |
|
694 |
static int |
|
695 |
auto_unmount(vfs_t *vfsp, int flag, cred_t *cr) |
|
696 |
{ |
|
697 |
fninfo_t *fnip; |
|
698 |
vnode_t *rvp; |
|
699 |
fnnode_t *rfnp, *fnp, *pfnp; |
|
700 |
fnnode_t *myrootfnnodep; |
|
701 |
||
702 |
fnip = vfstofni(vfsp); |
|
703 |
AUTOFS_DPRINT((4, "auto_unmount vfsp %p fnip %p\n", (void *)vfsp, |
|
11185
f0c31008e395
6887924 PP_ISKAS needs to be defined in terms of VN_ISKAS for vnodes
Sean McEnroe <Sean.McEnroe@Sun.COM>
parents:
4092
diff
changeset
|
704 |
(void *)fnip)); |
0 | 705 |
|
706 |
if (secpolicy_fs_unmount(cr, vfsp) != 0) |
|
707 |
return (EPERM); |
|
708 |
/* |
|
709 |
* forced unmount is not supported by this file system |
|
710 |
* and thus, ENOTSUP, is being returned. |
|
711 |
*/ |
|
712 |
if (flag & MS_FORCE) |
|
713 |
return (ENOTSUP); |
|
714 |
||
715 |
ASSERT(vn_vfswlock_held(vfsp->vfs_vnodecovered)); |
|
716 |
rvp = fnip->fi_rootvp; |
|
717 |
rfnp = vntofn(rvp); |
|
718 |
||
719 |
if (rvp->v_count > 1 || rfnp->fn_dirents != NULL) |
|
720 |
return (EBUSY); |
|
721 |
||
722 |
/* |
|
723 |
* The root vnode is on the linked list of root fnnodes only if |
|
724 |
* this was not a trigger node. Since we have no way of knowing, |
|
725 |
* if we don't find it, then we assume it was a trigger node. |
|
726 |
*/ |
|
727 |
myrootfnnodep = rfnp->fn_globals->fng_rootfnnodep; |
|
728 |
pfnp = NULL; |
|
729 |
rw_enter(&myrootfnnodep->fn_rwlock, RW_WRITER); |
|
730 |
fnp = myrootfnnodep->fn_dirents; |
|
731 |
while (fnp != NULL) { |
|
732 |
if (fnp == rfnp) { |
|
733 |
/* |
|
734 |
* A check here is made to see if rvp is busy. If |
|
735 |
* so, return EBUSY. Otherwise proceed with |
|
736 |
* disconnecting it from the list. |
|
737 |
*/ |
|
738 |
if (rvp->v_count > 1 || rfnp->fn_dirents != NULL) { |
|
739 |
rw_exit(&myrootfnnodep->fn_rwlock); |
|
740 |
return (EBUSY); |
|
741 |
} |
|
742 |
if (pfnp) |
|
743 |
pfnp->fn_next = fnp->fn_next; |
|
744 |
else |
|
745 |
myrootfnnodep->fn_dirents = fnp->fn_next; |
|
746 |
fnp->fn_next = NULL; |
|
747 |
break; |
|
748 |
} |
|
749 |
pfnp = fnp; |
|
750 |
fnp = fnp->fn_next; |
|
751 |
} |
|
752 |
rw_exit(&myrootfnnodep->fn_rwlock); |
|
753 |
||
754 |
ASSERT(rvp->v_count == 1); |
|
755 |
ASSERT(rfnp->fn_size == 1); |
|
756 |
ASSERT(rfnp->fn_linkcnt == 1); |
|
757 |
/* |
|
758 |
* The following drops linkcnt to 0, therefore the disconnect is |
|
759 |
* not attempted when auto_inactive() is called by |
|
760 |
* vn_rele(). This is necessary because we have nothing to get |
|
761 |
* disconnected from since we're the root of the filesystem. As a |
|
762 |
* side effect the node is not freed, therefore I should free the |
|
763 |
* node here. |
|
764 |
* |
|
765 |
* XXX - I really need to think of a better way of doing this. |
|
766 |
*/ |
|
767 |
rfnp->fn_size--; |
|
768 |
rfnp->fn_linkcnt--; |
|
769 |
||
770 |
/* |
|
771 |
* release of last reference causes node |
|
772 |
* to be freed |
|
773 |
*/ |
|
774 |
VN_RELE(rvp); |
|
775 |
rfnp->fn_parent = NULL; |
|
776 |
||
777 |
auto_freefnnode(rfnp); |
|
778 |
||
779 |
kmem_free(fnip->fi_addr.buf, fnip->fi_addr.len); |
|
780 |
kmem_free(fnip->fi_path, fnip->fi_pathlen); |
|
781 |
kmem_free(fnip->fi_map, fnip->fi_maplen); |
|
782 |
kmem_free(fnip->fi_subdir, fnip->fi_subdirlen); |
|
783 |
kmem_free(fnip->fi_key, fnip->fi_keylen); |
|
784 |
kmem_free(fnip->fi_opts, fnip->fi_optslen); |
|
785 |
kmem_free(fnip, sizeof (*fnip)); |
|
786 |
AUTOFS_DPRINT((5, "auto_unmount: return=0\n")); |
|
787 |
||
788 |
return (0); |
|
789 |
} |
|
790 |
||
791 |
||
792 |
/* |
|
793 |
* find root of autofs |
|
794 |
*/ |
|
795 |
static int |
|
796 |
auto_root(vfs_t *vfsp, vnode_t **vpp) |
|
797 |
{ |
|
798 |
*vpp = (vnode_t *)vfstofni(vfsp)->fi_rootvp; |
|
799 |
VN_HOLD(*vpp); |
|
800 |
||
801 |
AUTOFS_DPRINT((5, "auto_root: vfs %p, *vpp %p\n", (void *)vfsp, |
|
802 |
(void *)*vpp)); |
|
803 |
return (0); |
|
804 |
} |
|
805 |
||
806 |
/* |
|
807 |
* Get file system statistics. |
|
808 |
*/ |
|
809 |
static int |
|
810 |
auto_statvfs(vfs_t *vfsp, struct statvfs64 *sbp) |
|
811 |
{ |
|
812 |
dev32_t d32; |
|
813 |
||
814 |
AUTOFS_DPRINT((4, "auto_statvfs %p\n", (void *)vfsp)); |
|
815 |
||
816 |
bzero(sbp, sizeof (*sbp)); |
|
817 |
sbp->f_bsize = vfsp->vfs_bsize; |
|
818 |
sbp->f_frsize = sbp->f_bsize; |
|
819 |
sbp->f_blocks = (fsblkcnt64_t)0; |
|
820 |
sbp->f_bfree = (fsblkcnt64_t)0; |
|
821 |
sbp->f_bavail = (fsblkcnt64_t)0; |
|
822 |
sbp->f_files = (fsfilcnt64_t)0; |
|
823 |
sbp->f_ffree = (fsfilcnt64_t)0; |
|
824 |
sbp->f_favail = (fsfilcnt64_t)0; |
|
825 |
(void) cmpldev(&d32, vfsp->vfs_dev); |
|
826 |
sbp->f_fsid = d32; |
|
827 |
(void) strcpy(sbp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name); |
|
828 |
sbp->f_flag = vf_to_stf(vfsp->vfs_flag); |
|
829 |
sbp->f_namemax = MAXNAMELEN; |
|
830 |
(void) strcpy(sbp->f_fstr, MNTTYPE_AUTOFS); |
|
831 |
||
832 |
return (0); |
|
833 |
} |