author | Yuri Pankov <yuri.pankov@nexenta.com> |
Fri, 21 Sep 2012 06:38:43 +0400 | |
changeset 13832 | 8e4bcbc31a4a |
parent 13178 | 5f70b43d6386 |
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 |
/* |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
22 |
* Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 23 |
*/ |
24 |
||
25 |
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ |
|
26 |
/* All Rights Reserved */ |
|
27 |
||
28 |
/* |
|
29 |
* University Copyright- Copyright (c) 1982, 1986, 1988 |
|
30 |
* The Regents of the University of California |
|
31 |
* All Rights Reserved |
|
32 |
* |
|
33 |
* University Acknowledgment- Portions of this document are derived from |
|
34 |
* software developed by the University of California, Berkeley, and its |
|
35 |
* contributors. |
|
36 |
*/ |
|
37 |
||
38 |
#include <sys/types.h> |
|
39 |
#include <sys/t_lock.h> |
|
40 |
#include <sys/param.h> |
|
41 |
#include <sys/errno.h> |
|
42 |
#include <sys/user.h> |
|
43 |
#include <sys/fstyp.h> |
|
44 |
#include <sys/kmem.h> |
|
45 |
#include <sys/systm.h> |
|
46 |
#include <sys/proc.h> |
|
47 |
#include <sys/mount.h> |
|
48 |
#include <sys/vfs.h> |
|
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
49 |
#include <sys/vfs_opreg.h> |
0 | 50 |
#include <sys/fem.h> |
51 |
#include <sys/mntent.h> |
|
52 |
#include <sys/stat.h> |
|
53 |
#include <sys/statvfs.h> |
|
54 |
#include <sys/statfs.h> |
|
55 |
#include <sys/cred.h> |
|
56 |
#include <sys/vnode.h> |
|
57 |
#include <sys/rwstlock.h> |
|
58 |
#include <sys/dnlc.h> |
|
59 |
#include <sys/file.h> |
|
60 |
#include <sys/time.h> |
|
61 |
#include <sys/atomic.h> |
|
62 |
#include <sys/cmn_err.h> |
|
63 |
#include <sys/buf.h> |
|
64 |
#include <sys/swap.h> |
|
65 |
#include <sys/debug.h> |
|
66 |
#include <sys/vnode.h> |
|
67 |
#include <sys/modctl.h> |
|
68 |
#include <sys/ddi.h> |
|
69 |
#include <sys/pathname.h> |
|
70 |
#include <sys/bootconf.h> |
|
71 |
#include <sys/dumphdr.h> |
|
72 |
#include <sys/dc_ki.h> |
|
73 |
#include <sys/poll.h> |
|
74 |
#include <sys/sunddi.h> |
|
75 |
#include <sys/sysmacros.h> |
|
76 |
#include <sys/zone.h> |
|
77 |
#include <sys/policy.h> |
|
78 |
#include <sys/ctfs.h> |
|
79 |
#include <sys/objfs.h> |
|
80 |
#include <sys/console.h> |
|
81 |
#include <sys/reboot.h> |
|
5331 | 82 |
#include <sys/attr.h> |
10922
e2081f502306
PSARC 2009/571 ZFS Deduplication Properties
Jeff Bonwick <Jeff.Bonwick@Sun.COM>
parents:
10910
diff
changeset
|
83 |
#include <sys/zio.h> |
6423 | 84 |
#include <sys/spa.h> |
6734 | 85 |
#include <sys/lofi.h> |
8194 | 86 |
#include <sys/bootprops.h> |
0 | 87 |
|
88 |
#include <vm/page.h> |
|
89 |
||
90 |
#include <fs/fs_subr.h> |
|
1520 | 91 |
/* Private interfaces to create vopstats-related data structures */ |
92 |
extern void initialize_vopstats(vopstats_t *); |
|
93 |
extern vopstats_t *get_fstype_vopstats(struct vfs *, struct vfssw *); |
|
94 |
extern vsk_anchor_t *get_vskstat_anchor(struct vfs *); |
|
95 |
||
0 | 96 |
static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int); |
97 |
static void vfs_setmntopt_nolock(mntopts_t *, const char *, |
|
98 |
const char *, int, int); |
|
99 |
static int vfs_optionisset_nolock(const mntopts_t *, const char *, char **); |
|
100 |
static void vfs_freemnttab(struct vfs *); |
|
101 |
static void vfs_freeopt(mntopt_t *); |
|
102 |
static void vfs_swapopttbl_nolock(mntopts_t *, mntopts_t *); |
|
103 |
static void vfs_swapopttbl(mntopts_t *, mntopts_t *); |
|
104 |
static void vfs_copyopttbl_extend(const mntopts_t *, mntopts_t *, int); |
|
105 |
static void vfs_createopttbl_extend(mntopts_t *, const char *, |
|
106 |
const mntopts_t *); |
|
107 |
static char **vfs_copycancelopt_extend(char **const, int); |
|
108 |
static void vfs_freecancelopt(char **); |
|
5084 | 109 |
static void getrootfs(char **, char **); |
0 | 110 |
static int getmacpath(dev_info_t *, void *); |
4863 | 111 |
static void vfs_mnttabvp_setup(void); |
0 | 112 |
|
113 |
struct ipmnt { |
|
114 |
struct ipmnt *mip_next; |
|
115 |
dev_t mip_dev; |
|
116 |
struct vfs *mip_vfsp; |
|
117 |
}; |
|
118 |
||
119 |
static kmutex_t vfs_miplist_mutex; |
|
120 |
static struct ipmnt *vfs_miplist = NULL; |
|
121 |
static struct ipmnt *vfs_miplist_end = NULL; |
|
122 |
||
5331 | 123 |
static kmem_cache_t *vfs_cache; /* Pointer to VFS kmem cache */ |
124 |
||
0 | 125 |
/* |
126 |
* VFS global data. |
|
127 |
*/ |
|
128 |
vnode_t *rootdir; /* pointer to root inode vnode. */ |
|
129 |
vnode_t *devicesdir; /* pointer to inode of devices root */ |
|
2621 | 130 |
vnode_t *devdir; /* pointer to inode of dev root */ |
0 | 131 |
|
132 |
char *server_rootpath; /* root path for diskless clients */ |
|
133 |
char *server_hostname; /* hostname of diskless server */ |
|
134 |
||
135 |
static struct vfs root; |
|
136 |
static struct vfs devices; |
|
2621 | 137 |
static struct vfs dev; |
0 | 138 |
struct vfs *rootvfs = &root; /* pointer to root vfs; head of VFS list. */ |
139 |
rvfs_t *rvfs_list; /* array of vfs ptrs for vfs hash list */ |
|
140 |
int vfshsz = 512; /* # of heads/locks in vfs hash arrays */ |
|
141 |
/* must be power of 2! */ |
|
142 |
timespec_t vfs_mnttab_ctime; /* mnttab created time */ |
|
143 |
timespec_t vfs_mnttab_mtime; /* mnttab last modified time */ |
|
4813 | 144 |
char *vfs_dummyfstype = "\0"; |
0 | 145 |
struct pollhead vfs_pollhd; /* for mnttab pollers */ |
4863 | 146 |
struct vnode *vfs_mntdummyvp; /* to fake mnttab read/write for file events */ |
147 |
int mntfstype; /* will be set once mnt fs is mounted */ |
|
0 | 148 |
|
149 |
/* |
|
150 |
* Table for generic options recognized in the VFS layer and acted |
|
151 |
* on at this level before parsing file system specific options. |
|
152 |
* The nosuid option is stronger than any of the devices and setuid |
|
153 |
* options, so those are canceled when nosuid is seen. |
|
154 |
* |
|
155 |
* All options which are added here need to be added to the |
|
156 |
* list of standard options in usr/src/cmd/fs.d/fslib.c as well. |
|
157 |
*/ |
|
158 |
/* |
|
159 |
* VFS Mount options table |
|
160 |
*/ |
|
161 |
static char *ro_cancel[] = { MNTOPT_RW, NULL }; |
|
162 |
static char *rw_cancel[] = { MNTOPT_RO, NULL }; |
|
163 |
static char *suid_cancel[] = { MNTOPT_NOSUID, NULL }; |
|
164 |
static char *nosuid_cancel[] = { MNTOPT_SUID, MNTOPT_DEVICES, MNTOPT_NODEVICES, |
|
165 |
MNTOPT_NOSETUID, MNTOPT_SETUID, NULL }; |
|
166 |
static char *devices_cancel[] = { MNTOPT_NODEVICES, NULL }; |
|
167 |
static char *nodevices_cancel[] = { MNTOPT_DEVICES, NULL }; |
|
168 |
static char *setuid_cancel[] = { MNTOPT_NOSETUID, NULL }; |
|
169 |
static char *nosetuid_cancel[] = { MNTOPT_SETUID, NULL }; |
|
170 |
static char *nbmand_cancel[] = { MNTOPT_NONBMAND, NULL }; |
|
171 |
static char *nonbmand_cancel[] = { MNTOPT_NBMAND, NULL }; |
|
172 |
static char *exec_cancel[] = { MNTOPT_NOEXEC, NULL }; |
|
173 |
static char *noexec_cancel[] = { MNTOPT_EXEC, NULL }; |
|
174 |
||
175 |
static const mntopt_t mntopts[] = { |
|
176 |
/* |
|
177 |
* option name cancel options default arg flags |
|
178 |
*/ |
|
179 |
{ MNTOPT_REMOUNT, NULL, NULL, |
|
180 |
MO_NODISPLAY, (void *)0 }, |
|
181 |
{ MNTOPT_RO, ro_cancel, NULL, 0, |
|
182 |
(void *)0 }, |
|
183 |
{ MNTOPT_RW, rw_cancel, NULL, 0, |
|
184 |
(void *)0 }, |
|
185 |
{ MNTOPT_SUID, suid_cancel, NULL, 0, |
|
186 |
(void *)0 }, |
|
187 |
{ MNTOPT_NOSUID, nosuid_cancel, NULL, 0, |
|
188 |
(void *)0 }, |
|
189 |
{ MNTOPT_DEVICES, devices_cancel, NULL, 0, |
|
190 |
(void *)0 }, |
|
191 |
{ MNTOPT_NODEVICES, nodevices_cancel, NULL, 0, |
|
192 |
(void *)0 }, |
|
193 |
{ MNTOPT_SETUID, setuid_cancel, NULL, 0, |
|
194 |
(void *)0 }, |
|
195 |
{ MNTOPT_NOSETUID, nosetuid_cancel, NULL, 0, |
|
196 |
(void *)0 }, |
|
197 |
{ MNTOPT_NBMAND, nbmand_cancel, NULL, 0, |
|
198 |
(void *)0 }, |
|
199 |
{ MNTOPT_NONBMAND, nonbmand_cancel, NULL, 0, |
|
200 |
(void *)0 }, |
|
201 |
{ MNTOPT_EXEC, exec_cancel, NULL, 0, |
|
202 |
(void *)0 }, |
|
203 |
{ MNTOPT_NOEXEC, noexec_cancel, NULL, 0, |
|
204 |
(void *)0 }, |
|
205 |
}; |
|
206 |
||
207 |
const mntopts_t vfs_mntopts = { |
|
208 |
sizeof (mntopts) / sizeof (mntopt_t), |
|
209 |
(mntopt_t *)&mntopts[0] |
|
210 |
}; |
|
211 |
||
212 |
/* |
|
213 |
* File system operation dispatch functions. |
|
214 |
*/ |
|
215 |
||
216 |
int |
|
217 |
fsop_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) |
|
218 |
{ |
|
219 |
return (*(vfsp)->vfs_op->vfs_mount)(vfsp, mvp, uap, cr); |
|
220 |
} |
|
221 |
||
222 |
int |
|
223 |
fsop_unmount(vfs_t *vfsp, int flag, cred_t *cr) |
|
224 |
{ |
|
225 |
return (*(vfsp)->vfs_op->vfs_unmount)(vfsp, flag, cr); |
|
226 |
} |
|
227 |
||
228 |
int |
|
229 |
fsop_root(vfs_t *vfsp, vnode_t **vpp) |
|
230 |
{ |
|
231 |
refstr_t *mntpt; |
|
232 |
int ret = (*(vfsp)->vfs_op->vfs_root)(vfsp, vpp); |
|
233 |
/* |
|
234 |
* Make sure this root has a path. With lofs, it is possible to have |
|
235 |
* a NULL mountpoint. |
|
236 |
*/ |
|
254
349581d9fc98
6175313 io provider exposes our reluctance to set vnode paths
eschrock
parents:
0
diff
changeset
|
237 |
if (ret == 0 && vfsp->vfs_mntpt != NULL && (*vpp)->v_path == NULL) { |
0 | 238 |
mntpt = vfs_getmntpoint(vfsp); |
239 |
vn_setpath_str(*vpp, refstr_value(mntpt), |
|
240 |
strlen(refstr_value(mntpt))); |
|
241 |
refstr_rele(mntpt); |
|
242 |
} |
|
243 |
||
244 |
return (ret); |
|
245 |
} |
|
246 |
||
247 |
int |
|
248 |
fsop_statfs(vfs_t *vfsp, statvfs64_t *sp) |
|
249 |
{ |
|
250 |
return (*(vfsp)->vfs_op->vfs_statvfs)(vfsp, sp); |
|
251 |
} |
|
252 |
||
253 |
int |
|
254 |
fsop_sync(vfs_t *vfsp, short flag, cred_t *cr) |
|
255 |
{ |
|
256 |
return (*(vfsp)->vfs_op->vfs_sync)(vfsp, flag, cr); |
|
257 |
} |
|
258 |
||
259 |
int |
|
260 |
fsop_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp) |
|
261 |
{ |
|
5331 | 262 |
/* |
263 |
* In order to handle system attribute fids in a manner |
|
264 |
* transparent to the underlying fs, we embed the fid for |
|
265 |
* the sysattr parent object in the sysattr fid and tack on |
|
266 |
* some extra bytes that only the sysattr layer knows about. |
|
267 |
* |
|
268 |
* This guarantees that sysattr fids are larger than other fids |
|
7757
bf4a45ecb669
PSARC/2008/588 VFSFT_SYSATTR_VIEWS
Janice Chang <Janice.Chang@Sun.COM>
parents:
7439
diff
changeset
|
269 |
* for this vfs. If the vfs supports the sysattr view interface |
bf4a45ecb669
PSARC/2008/588 VFSFT_SYSATTR_VIEWS
Janice Chang <Janice.Chang@Sun.COM>
parents:
7439
diff
changeset
|
270 |
* (as indicated by VFSFT_SYSATTR_VIEWS), we cannot have a size |
bf4a45ecb669
PSARC/2008/588 VFSFT_SYSATTR_VIEWS
Janice Chang <Janice.Chang@Sun.COM>
parents:
7439
diff
changeset
|
271 |
* collision with XATTR_FIDSZ. |
5331 | 272 |
*/ |
7757
bf4a45ecb669
PSARC/2008/588 VFSFT_SYSATTR_VIEWS
Janice Chang <Janice.Chang@Sun.COM>
parents:
7439
diff
changeset
|
273 |
if (vfs_has_feature(vfsp, VFSFT_SYSATTR_VIEWS) && |
5331 | 274 |
fidp->fid_len == XATTR_FIDSZ) |
275 |
return (xattr_dir_vget(vfsp, vpp, fidp)); |
|
276 |
||
0 | 277 |
return (*(vfsp)->vfs_op->vfs_vget)(vfsp, vpp, fidp); |
278 |
} |
|
279 |
||
280 |
int |
|
281 |
fsop_mountroot(vfs_t *vfsp, enum whymountroot reason) |
|
282 |
{ |
|
283 |
return (*(vfsp)->vfs_op->vfs_mountroot)(vfsp, reason); |
|
284 |
} |
|
285 |
||
286 |
void |
|
287 |
fsop_freefs(vfs_t *vfsp) |
|
288 |
{ |
|
289 |
(*(vfsp)->vfs_op->vfs_freevfs)(vfsp); |
|
290 |
} |
|
291 |
||
292 |
int |
|
293 |
fsop_vnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t nstate) |
|
294 |
{ |
|
295 |
return ((*(vfsp)->vfs_op->vfs_vnstate)(vfsp, vp, nstate)); |
|
296 |
} |
|
297 |
||
298 |
int |
|
299 |
fsop_sync_by_kind(int fstype, short flag, cred_t *cr) |
|
300 |
{ |
|
301 |
ASSERT((fstype >= 0) && (fstype < nfstype)); |
|
302 |
||
303 |
if (ALLOCATED_VFSSW(&vfssw[fstype]) && VFS_INSTALLED(&vfssw[fstype])) |
|
304 |
return (*vfssw[fstype].vsw_vfsops.vfs_sync) (NULL, flag, cr); |
|
305 |
else |
|
306 |
return (ENOTSUP); |
|
307 |
} |
|
308 |
||
309 |
/* |
|
310 |
* File system initialization. vfs_setfsops() must be called from a file |
|
311 |
* system's init routine. |
|
312 |
*/ |
|
313 |
||
314 |
static int |
|
315 |
fs_copyfsops(const fs_operation_def_t *template, vfsops_t *actual, |
|
316 |
int *unused_ops) |
|
317 |
{ |
|
318 |
static const fs_operation_trans_def_t vfs_ops_table[] = { |
|
319 |
VFSNAME_MOUNT, offsetof(vfsops_t, vfs_mount), |
|
320 |
fs_nosys, fs_nosys, |
|
321 |
||
322 |
VFSNAME_UNMOUNT, offsetof(vfsops_t, vfs_unmount), |
|
323 |
fs_nosys, fs_nosys, |
|
324 |
||
325 |
VFSNAME_ROOT, offsetof(vfsops_t, vfs_root), |
|
326 |
fs_nosys, fs_nosys, |
|
327 |
||
328 |
VFSNAME_STATVFS, offsetof(vfsops_t, vfs_statvfs), |
|
329 |
fs_nosys, fs_nosys, |
|
330 |
||
331 |
VFSNAME_SYNC, offsetof(vfsops_t, vfs_sync), |
|
332 |
(fs_generic_func_p) fs_sync, |
|
333 |
(fs_generic_func_p) fs_sync, /* No errors allowed */ |
|
334 |
||
335 |
VFSNAME_VGET, offsetof(vfsops_t, vfs_vget), |
|
336 |
fs_nosys, fs_nosys, |
|
337 |
||
338 |
VFSNAME_MOUNTROOT, offsetof(vfsops_t, vfs_mountroot), |
|
339 |
fs_nosys, fs_nosys, |
|
340 |
||
341 |
VFSNAME_FREEVFS, offsetof(vfsops_t, vfs_freevfs), |
|
342 |
(fs_generic_func_p)fs_freevfs, |
|
343 |
(fs_generic_func_p)fs_freevfs, /* Shouldn't fail */ |
|
344 |
||
345 |
VFSNAME_VNSTATE, offsetof(vfsops_t, vfs_vnstate), |
|
346 |
(fs_generic_func_p)fs_nosys, |
|
347 |
(fs_generic_func_p)fs_nosys, |
|
348 |
||
349 |
NULL, 0, NULL, NULL |
|
350 |
}; |
|
351 |
||
352 |
return (fs_build_vector(actual, unused_ops, vfs_ops_table, template)); |
|
353 |
} |
|
354 |
||
6423 | 355 |
void |
356 |
zfs_boot_init() { |
|
357 |
||
358 |
if (strcmp(rootfs.bo_fstype, MNTTYPE_ZFS) == 0) |
|
359 |
spa_boot_init(); |
|
360 |
} |
|
361 |
||
0 | 362 |
int |
363 |
vfs_setfsops(int fstype, const fs_operation_def_t *template, vfsops_t **actual) |
|
364 |
{ |
|
365 |
int error; |
|
366 |
int unused_ops; |
|
367 |
||
3904 | 368 |
/* |
369 |
* Verify that fstype refers to a valid fs. Note that |
|
370 |
* 0 is valid since it's used to set "stray" ops. |
|
371 |
*/ |
|
372 |
if ((fstype < 0) || (fstype >= nfstype)) |
|
0 | 373 |
return (EINVAL); |
374 |
||
375 |
if (!ALLOCATED_VFSSW(&vfssw[fstype])) |
|
376 |
return (EINVAL); |
|
377 |
||
378 |
/* Set up the operations vector. */ |
|
379 |
||
380 |
error = fs_copyfsops(template, &vfssw[fstype].vsw_vfsops, &unused_ops); |
|
381 |
||
382 |
if (error != 0) |
|
383 |
return (error); |
|
384 |
||
385 |
vfssw[fstype].vsw_flag |= VSW_INSTALLED; |
|
386 |
||
387 |
if (actual != NULL) |
|
388 |
*actual = &vfssw[fstype].vsw_vfsops; |
|
389 |
||
390 |
#if DEBUG |
|
391 |
if (unused_ops != 0) |
|
392 |
cmn_err(CE_WARN, "vfs_setfsops: %s: %d operations supplied " |
|
393 |
"but not used", vfssw[fstype].vsw_name, unused_ops); |
|
394 |
#endif |
|
395 |
||
396 |
return (0); |
|
397 |
} |
|
398 |
||
399 |
int |
|
400 |
vfs_makefsops(const fs_operation_def_t *template, vfsops_t **actual) |
|
401 |
{ |
|
402 |
int error; |
|
403 |
int unused_ops; |
|
404 |
||
405 |
*actual = (vfsops_t *)kmem_alloc(sizeof (vfsops_t), KM_SLEEP); |
|
406 |
||
407 |
error = fs_copyfsops(template, *actual, &unused_ops); |
|
408 |
if (error != 0) { |
|
409 |
kmem_free(*actual, sizeof (vfsops_t)); |
|
410 |
*actual = NULL; |
|
411 |
return (error); |
|
412 |
} |
|
413 |
||
414 |
return (0); |
|
415 |
} |
|
416 |
||
417 |
/* |
|
418 |
* Free a vfsops structure created as a result of vfs_makefsops(). |
|
419 |
* NOTE: For a vfsops structure initialized by vfs_setfsops(), use |
|
420 |
* vfs_freevfsops_by_type(). |
|
421 |
*/ |
|
422 |
void |
|
423 |
vfs_freevfsops(vfsops_t *vfsops) |
|
424 |
{ |
|
425 |
kmem_free(vfsops, sizeof (vfsops_t)); |
|
426 |
} |
|
427 |
||
428 |
/* |
|
429 |
* Since the vfsops structure is part of the vfssw table and wasn't |
|
430 |
* really allocated, we're not really freeing anything. We keep |
|
431 |
* the name for consistency with vfs_freevfsops(). We do, however, |
|
432 |
* need to take care of a little bookkeeping. |
|
433 |
* NOTE: For a vfsops structure created by vfs_setfsops(), use |
|
434 |
* vfs_freevfsops_by_type(). |
|
435 |
*/ |
|
436 |
int |
|
437 |
vfs_freevfsops_by_type(int fstype) |
|
438 |
{ |
|
439 |
||
440 |
/* Verify that fstype refers to a loaded fs (and not fsid 0). */ |
|
441 |
if ((fstype <= 0) || (fstype >= nfstype)) |
|
442 |
return (EINVAL); |
|
443 |
||
444 |
WLOCK_VFSSW(); |
|
445 |
if ((vfssw[fstype].vsw_flag & VSW_INSTALLED) == 0) { |
|
446 |
WUNLOCK_VFSSW(); |
|
447 |
return (EINVAL); |
|
448 |
} |
|
449 |
||
450 |
vfssw[fstype].vsw_flag &= ~VSW_INSTALLED; |
|
451 |
WUNLOCK_VFSSW(); |
|
452 |
||
453 |
return (0); |
|
454 |
} |
|
455 |
||
456 |
/* Support routines used to reference vfs_op */ |
|
457 |
||
458 |
/* Set the operations vector for a vfs */ |
|
459 |
void |
|
460 |
vfs_setops(vfs_t *vfsp, vfsops_t *vfsops) |
|
461 |
{ |
|
462 |
vfsops_t *op; |
|
463 |
||
464 |
ASSERT(vfsp != NULL); |
|
465 |
ASSERT(vfsops != NULL); |
|
466 |
||
467 |
op = vfsp->vfs_op; |
|
468 |
membar_consumer(); |
|
5331 | 469 |
if (vfsp->vfs_femhead == NULL && |
0 | 470 |
casptr(&vfsp->vfs_op, op, vfsops) == op) { |
471 |
return; |
|
472 |
} |
|
473 |
fsem_setvfsops(vfsp, vfsops); |
|
474 |
} |
|
475 |
||
476 |
/* Retrieve the operations vector for a vfs */ |
|
477 |
vfsops_t * |
|
478 |
vfs_getops(vfs_t *vfsp) |
|
479 |
{ |
|
480 |
vfsops_t *op; |
|
481 |
||
482 |
ASSERT(vfsp != NULL); |
|
483 |
||
484 |
op = vfsp->vfs_op; |
|
485 |
membar_consumer(); |
|
5331 | 486 |
if (vfsp->vfs_femhead == NULL && op == vfsp->vfs_op) { |
0 | 487 |
return (op); |
488 |
} else { |
|
489 |
return (fsem_getvfsops(vfsp)); |
|
490 |
} |
|
491 |
} |
|
492 |
||
493 |
/* |
|
494 |
* Returns non-zero (1) if the vfsops matches that of the vfs. |
|
495 |
* Returns zero (0) if not. |
|
496 |
*/ |
|
497 |
int |
|
498 |
vfs_matchops(vfs_t *vfsp, vfsops_t *vfsops) |
|
499 |
{ |
|
500 |
return (vfs_getops(vfsp) == vfsops); |
|
501 |
} |
|
502 |
||
503 |
/* |
|
504 |
* Returns non-zero (1) if the file system has installed a non-default, |
|
505 |
* non-error vfs_sync routine. Returns zero (0) otherwise. |
|
506 |
*/ |
|
507 |
int |
|
508 |
vfs_can_sync(vfs_t *vfsp) |
|
509 |
{ |
|
510 |
/* vfs_sync() routine is not the default/error function */ |
|
511 |
return (vfs_getops(vfsp)->vfs_sync != fs_sync); |
|
512 |
} |
|
513 |
||
514 |
/* |
|
515 |
* Initialize a vfs structure. |
|
516 |
*/ |
|
517 |
void |
|
518 |
vfs_init(vfs_t *vfsp, vfsops_t *op, void *data) |
|
519 |
{ |
|
5331 | 520 |
/* Other initialization has been moved to vfs_alloc() */ |
0 | 521 |
vfsp->vfs_count = 0; |
522 |
vfsp->vfs_next = vfsp; |
|
523 |
vfsp->vfs_prev = vfsp; |
|
524 |
vfsp->vfs_zone_next = vfsp; |
|
525 |
vfsp->vfs_zone_prev = vfsp; |
|
6734 | 526 |
vfsp->vfs_lofi_minor = 0; |
5331 | 527 |
sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL); |
528 |
vfsimpl_setup(vfsp); |
|
0 | 529 |
vfsp->vfs_data = (data); |
530 |
vfs_setops((vfsp), (op)); |
|
531 |
} |
|
532 |
||
1925 | 533 |
/* |
534 |
* Allocate and initialize the vfs implementation private data |
|
535 |
* structure, vfs_impl_t. |
|
536 |
*/ |
|
537 |
void |
|
538 |
vfsimpl_setup(vfs_t *vfsp) |
|
539 |
{ |
|
5331 | 540 |
int i; |
541 |
||
542 |
if (vfsp->vfs_implp != NULL) { |
|
543 |
return; |
|
544 |
} |
|
545 |
||
1925 | 546 |
vfsp->vfs_implp = kmem_alloc(sizeof (vfs_impl_t), KM_SLEEP); |
5331 | 547 |
/* Note that these are #define'd in vfs.h */ |
1925 | 548 |
vfsp->vfs_vskap = NULL; |
549 |
vfsp->vfs_fstypevsp = NULL; |
|
5331 | 550 |
|
551 |
/* Set size of counted array, then zero the array */ |
|
552 |
vfsp->vfs_featureset[0] = VFS_FEATURE_MAXSZ - 1; |
|
553 |
for (i = 1; i < VFS_FEATURE_MAXSZ; i++) { |
|
554 |
vfsp->vfs_featureset[i] = 0; |
|
555 |
} |
|
1925 | 556 |
} |
557 |
||
558 |
/* |
|
559 |
* Release the vfs_impl_t structure, if it exists. Some unbundled |
|
560 |
* filesystems may not use the newer version of vfs and thus |
|
561 |
* would not contain this implementation private data structure. |
|
562 |
*/ |
|
563 |
void |
|
564 |
vfsimpl_teardown(vfs_t *vfsp) |
|
565 |
{ |
|
566 |
vfs_impl_t *vip = vfsp->vfs_implp; |
|
567 |
||
568 |
if (vip == NULL) |
|
569 |
return; |
|
570 |
||
571 |
kmem_free(vfsp->vfs_implp, sizeof (vfs_impl_t)); |
|
572 |
vfsp->vfs_implp = NULL; |
|
573 |
} |
|
0 | 574 |
|
575 |
/* |
|
576 |
* VFS system calls: mount, umount, syssync, statfs, fstatfs, statvfs, |
|
577 |
* fstatvfs, and sysfs moved to common/syscall. |
|
578 |
*/ |
|
579 |
||
580 |
/* |
|
581 |
* Update every mounted file system. We call the vfs_sync operation of |
|
582 |
* each file system type, passing it a NULL vfsp to indicate that all |
|
583 |
* mounted file systems of that type should be updated. |
|
584 |
*/ |
|
585 |
void |
|
586 |
vfs_sync(int flag) |
|
587 |
{ |
|
588 |
struct vfssw *vswp; |
|
589 |
RLOCK_VFSSW(); |
|
590 |
for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { |
|
591 |
if (ALLOCATED_VFSSW(vswp) && VFS_INSTALLED(vswp)) { |
|
592 |
vfs_refvfssw(vswp); |
|
593 |
RUNLOCK_VFSSW(); |
|
594 |
(void) (*vswp->vsw_vfsops.vfs_sync)(NULL, flag, |
|
595 |
CRED()); |
|
596 |
vfs_unrefvfssw(vswp); |
|
597 |
RLOCK_VFSSW(); |
|
598 |
} |
|
599 |
} |
|
600 |
RUNLOCK_VFSSW(); |
|
601 |
} |
|
602 |
||
603 |
void |
|
604 |
sync(void) |
|
605 |
{ |
|
606 |
vfs_sync(0); |
|
607 |
} |
|
608 |
||
609 |
/* |
|
610 |
* External routines. |
|
611 |
*/ |
|
612 |
||
613 |
krwlock_t vfssw_lock; /* lock accesses to vfssw */ |
|
614 |
||
615 |
/* |
|
616 |
* Lock for accessing the vfs linked list. Initialized in vfs_mountroot(), |
|
617 |
* but otherwise should be accessed only via vfs_list_lock() and |
|
618 |
* vfs_list_unlock(). Also used to protect the timestamp for mods to the list. |
|
619 |
*/ |
|
620 |
static krwlock_t vfslist; |
|
621 |
||
622 |
/* |
|
623 |
* Mount devfs on /devices. This is done right after root is mounted |
|
624 |
* to provide device access support for the system |
|
625 |
*/ |
|
626 |
static void |
|
627 |
vfs_mountdevices(void) |
|
628 |
{ |
|
629 |
struct vfssw *vsw; |
|
630 |
struct vnode *mvp; |
|
631 |
struct mounta mounta = { /* fake mounta for devfs_mount() */ |
|
632 |
NULL, |
|
633 |
NULL, |
|
634 |
MS_SYSSPACE, |
|
635 |
NULL, |
|
636 |
NULL, |
|
637 |
0, |
|
638 |
NULL, |
|
639 |
0 |
|
640 |
}; |
|
641 |
||
642 |
/* |
|
643 |
* _init devfs module to fill in the vfssw |
|
644 |
*/ |
|
645 |
if (modload("fs", "devfs") == -1) |
|
3446 | 646 |
panic("Cannot _init devfs module"); |
0 | 647 |
|
648 |
/* |
|
649 |
* Hold vfs |
|
650 |
*/ |
|
651 |
RLOCK_VFSSW(); |
|
652 |
vsw = vfs_getvfsswbyname("devfs"); |
|
653 |
VFS_INIT(&devices, &vsw->vsw_vfsops, NULL); |
|
654 |
VFS_HOLD(&devices); |
|
655 |
||
656 |
/* |
|
657 |
* Locate mount point |
|
658 |
*/ |
|
659 |
if (lookupname("/devices", UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp)) |
|
3446 | 660 |
panic("Cannot find /devices"); |
0 | 661 |
|
662 |
/* |
|
663 |
* Perform the mount of /devices |
|
664 |
*/ |
|
665 |
if (VFS_MOUNT(&devices, mvp, &mounta, CRED())) |
|
3446 | 666 |
panic("Cannot mount /devices"); |
0 | 667 |
|
668 |
RUNLOCK_VFSSW(); |
|
669 |
||
670 |
/* |
|
671 |
* Set appropriate members and add to vfs list for mnttab display |
|
672 |
*/ |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
673 |
vfs_setresource(&devices, "/devices", 0); |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
674 |
vfs_setmntpoint(&devices, "/devices", 0); |
0 | 675 |
|
676 |
/* |
|
677 |
* Hold the root of /devices so it won't go away |
|
678 |
*/ |
|
679 |
if (VFS_ROOT(&devices, &devicesdir)) |
|
3446 | 680 |
panic("vfs_mountdevices: not devices root"); |
0 | 681 |
|
682 |
if (vfs_lock(&devices) != 0) { |
|
2621 | 683 |
VN_RELE(devicesdir); |
0 | 684 |
cmn_err(CE_NOTE, "Cannot acquire vfs_lock of /devices"); |
685 |
return; |
|
686 |
} |
|
687 |
||
688 |
if (vn_vfswlock(mvp) != 0) { |
|
689 |
vfs_unlock(&devices); |
|
2621 | 690 |
VN_RELE(devicesdir); |
0 | 691 |
cmn_err(CE_NOTE, "Cannot acquire vfswlock of /devices"); |
692 |
return; |
|
693 |
} |
|
694 |
||
695 |
vfs_add(mvp, &devices, 0); |
|
696 |
vn_vfsunlock(mvp); |
|
697 |
vfs_unlock(&devices); |
|
2621 | 698 |
VN_RELE(devicesdir); |
699 |
} |
|
700 |
||
701 |
/* |
|
702 |
* mount the first instance of /dev to root and remain mounted |
|
703 |
*/ |
|
704 |
static void |
|
705 |
vfs_mountdev1(void) |
|
706 |
{ |
|
707 |
struct vfssw *vsw; |
|
708 |
struct vnode *mvp; |
|
709 |
struct mounta mounta = { /* fake mounta for sdev_mount() */ |
|
710 |
NULL, |
|
711 |
NULL, |
|
712 |
MS_SYSSPACE | MS_OVERLAY, |
|
713 |
NULL, |
|
714 |
NULL, |
|
715 |
0, |
|
716 |
NULL, |
|
717 |
0 |
|
718 |
}; |
|
719 |
||
720 |
/* |
|
721 |
* _init dev module to fill in the vfssw |
|
722 |
*/ |
|
723 |
if (modload("fs", "dev") == -1) |
|
724 |
cmn_err(CE_PANIC, "Cannot _init dev module\n"); |
|
725 |
||
726 |
/* |
|
727 |
* Hold vfs |
|
728 |
*/ |
|
729 |
RLOCK_VFSSW(); |
|
730 |
vsw = vfs_getvfsswbyname("dev"); |
|
731 |
VFS_INIT(&dev, &vsw->vsw_vfsops, NULL); |
|
732 |
VFS_HOLD(&dev); |
|
733 |
||
734 |
/* |
|
735 |
* Locate mount point |
|
736 |
*/ |
|
737 |
if (lookupname("/dev", UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp)) |
|
738 |
cmn_err(CE_PANIC, "Cannot find /dev\n"); |
|
739 |
||
740 |
/* |
|
741 |
* Perform the mount of /dev |
|
742 |
*/ |
|
743 |
if (VFS_MOUNT(&dev, mvp, &mounta, CRED())) |
|
744 |
cmn_err(CE_PANIC, "Cannot mount /dev 1\n"); |
|
745 |
||
746 |
RUNLOCK_VFSSW(); |
|
747 |
||
748 |
/* |
|
749 |
* Set appropriate members and add to vfs list for mnttab display |
|
750 |
*/ |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
751 |
vfs_setresource(&dev, "/dev", 0); |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
752 |
vfs_setmntpoint(&dev, "/dev", 0); |
2621 | 753 |
|
754 |
/* |
|
755 |
* Hold the root of /dev so it won't go away |
|
756 |
*/ |
|
757 |
if (VFS_ROOT(&dev, &devdir)) |
|
758 |
cmn_err(CE_PANIC, "vfs_mountdev1: not dev root"); |
|
759 |
||
760 |
if (vfs_lock(&dev) != 0) { |
|
761 |
VN_RELE(devdir); |
|
762 |
cmn_err(CE_NOTE, "Cannot acquire vfs_lock of /dev"); |
|
763 |
return; |
|
764 |
} |
|
765 |
||
766 |
if (vn_vfswlock(mvp) != 0) { |
|
767 |
vfs_unlock(&dev); |
|
768 |
VN_RELE(devdir); |
|
769 |
cmn_err(CE_NOTE, "Cannot acquire vfswlock of /dev"); |
|
770 |
return; |
|
771 |
} |
|
772 |
||
773 |
vfs_add(mvp, &dev, 0); |
|
774 |
vn_vfsunlock(mvp); |
|
775 |
vfs_unlock(&dev); |
|
776 |
VN_RELE(devdir); |
|
0 | 777 |
} |
778 |
||
779 |
/* |
|
780 |
* Mount required filesystem. This is done right after root is mounted. |
|
781 |
*/ |
|
782 |
static void |
|
783 |
vfs_mountfs(char *module, char *spec, char *path) |
|
784 |
{ |
|
785 |
struct vnode *mvp; |
|
786 |
struct mounta mounta; |
|
787 |
vfs_t *vfsp; |
|
788 |
||
789 |
mounta.flags = MS_SYSSPACE | MS_DATA; |
|
790 |
mounta.fstype = module; |
|
791 |
mounta.spec = spec; |
|
792 |
mounta.dir = path; |
|
793 |
if (lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &mvp)) { |
|
3446 | 794 |
cmn_err(CE_WARN, "Cannot find %s", path); |
0 | 795 |
return; |
796 |
} |
|
797 |
if (domount(NULL, &mounta, mvp, CRED(), &vfsp)) |
|
3446 | 798 |
cmn_err(CE_WARN, "Cannot mount %s", path); |
0 | 799 |
else |
800 |
VFS_RELE(vfsp); |
|
801 |
VN_RELE(mvp); |
|
802 |
} |
|
803 |
||
804 |
/* |
|
805 |
* vfs_mountroot is called by main() to mount the root filesystem. |
|
806 |
*/ |
|
807 |
void |
|
808 |
vfs_mountroot(void) |
|
809 |
{ |
|
810 |
struct vnode *rvp = NULL; |
|
811 |
char *path; |
|
812 |
size_t plen; |
|
1488 | 813 |
struct vfssw *vswp; |
11173
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
814 |
proc_t *p; |
0 | 815 |
|
816 |
rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL); |
|
817 |
rw_init(&vfslist, NULL, RW_DEFAULT, NULL); |
|
818 |
||
819 |
/* |
|
820 |
* Alloc the vfs hash bucket array and locks |
|
821 |
*/ |
|
822 |
rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP); |
|
823 |
||
824 |
/* |
|
825 |
* Call machine-dependent routine "rootconf" to choose a root |
|
826 |
* file system type. |
|
827 |
*/ |
|
828 |
if (rootconf()) |
|
3446 | 829 |
panic("vfs_mountroot: cannot mount root"); |
0 | 830 |
/* |
831 |
* Get vnode for '/'. Set up rootdir, u.u_rdir and u.u_cdir |
|
832 |
* to point to it. These are used by lookuppn() so that it |
|
833 |
* knows where to start from ('/' or '.'). |
|
834 |
*/ |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
835 |
vfs_setmntpoint(rootvfs, "/", 0); |
0 | 836 |
if (VFS_ROOT(rootvfs, &rootdir)) |
3446 | 837 |
panic("vfs_mountroot: no root vnode"); |
11173
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
838 |
|
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
839 |
/* |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
840 |
* At this point, the process tree consists of p0 and possibly some |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
841 |
* direct children of p0. (i.e. there are no grandchildren) |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
842 |
* |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
843 |
* Walk through them all, setting their current directory. |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
844 |
*/ |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
845 |
mutex_enter(&pidlock); |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
846 |
for (p = practive; p != NULL; p = p->p_next) { |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
847 |
ASSERT(p == &p0 || p->p_parent == &p0); |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
848 |
|
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
849 |
PTOU(p)->u_cdir = rootdir; |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
850 |
VN_HOLD(PTOU(p)->u_cdir); |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
851 |
PTOU(p)->u_rdir = NULL; |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
852 |
} |
87f3734e64df
6881015 ZFS write activity prevents other threads from running in a timely manner
Jonathan Adams <Jonathan.Adams@Sun.COM>
parents:
11005
diff
changeset
|
853 |
mutex_exit(&pidlock); |
0 | 854 |
|
855 |
/* |
|
856 |
* Setup the global zone's rootvp, now that it exists. |
|
857 |
*/ |
|
858 |
global_zone->zone_rootvp = rootdir; |
|
859 |
VN_HOLD(global_zone->zone_rootvp); |
|
860 |
||
861 |
/* |
|
862 |
* Notify the module code that it can begin using the |
|
863 |
* root filesystem instead of the boot program's services. |
|
864 |
*/ |
|
865 |
modrootloaded = 1; |
|
6423 | 866 |
|
867 |
/* |
|
868 |
* Special handling for a ZFS root file system. |
|
869 |
*/ |
|
870 |
zfs_boot_init(); |
|
871 |
||
0 | 872 |
/* |
873 |
* Set up mnttab information for root |
|
874 |
*/ |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
875 |
vfs_setresource(rootvfs, rootfs.bo_name, 0); |
0 | 876 |
|
877 |
/* |
|
878 |
* Notify cluster software that the root filesystem is available. |
|
879 |
*/ |
|
880 |
clboot_mountroot(); |
|
881 |
||
1488 | 882 |
/* Now that we're all done with the root FS, set up its vopstats */ |
883 |
if ((vswp = vfs_getvfsswbyvfsops(vfs_getops(rootvfs))) != NULL) { |
|
884 |
/* Set flag for statistics collection */ |
|
885 |
if (vswp->vsw_flag & VSW_STATS) { |
|
1520 | 886 |
initialize_vopstats(&rootvfs->vfs_vopstats); |
1488 | 887 |
rootvfs->vfs_flag |= VFS_STATS; |
1520 | 888 |
rootvfs->vfs_fstypevsp = |
889 |
get_fstype_vopstats(rootvfs, vswp); |
|
890 |
rootvfs->vfs_vskap = get_vskstat_anchor(rootvfs); |
|
1488 | 891 |
} |
892 |
vfs_unrefvfssw(vswp); |
|
893 |
} |
|
894 |
||
0 | 895 |
/* |
2621 | 896 |
* Mount /devices, /dev instance 1, /system/contract, /etc/mnttab, |
3957 | 897 |
* /etc/svc/volatile, /etc/dfs/sharetab, /system/object, and /proc. |
0 | 898 |
*/ |
899 |
vfs_mountdevices(); |
|
2621 | 900 |
vfs_mountdev1(); |
0 | 901 |
|
902 |
vfs_mountfs("ctfs", "ctfs", CTFS_ROOT); |
|
903 |
vfs_mountfs("proc", "/proc", "/proc"); |
|
904 |
vfs_mountfs("mntfs", "/etc/mnttab", "/etc/mnttab"); |
|
905 |
vfs_mountfs("tmpfs", "/etc/svc/volatile", "/etc/svc/volatile"); |
|
906 |
vfs_mountfs("objfs", "objfs", OBJFS_ROOT); |
|
907 |
||
3957 | 908 |
if (getzoneid() == GLOBAL_ZONEID) { |
909 |
vfs_mountfs("sharefs", "sharefs", "/etc/dfs/sharetab"); |
|
910 |
} |
|
911 |
||
0 | 912 |
#ifdef __sparc |
913 |
/* |
|
914 |
* This bit of magic can go away when we convert sparc to |
|
915 |
* the new boot architecture based on ramdisk. |
|
916 |
* |
|
917 |
* Booting off a mirrored root volume: |
|
918 |
* At this point, we have booted and mounted root on a |
|
919 |
* single component of the mirror. Complete the boot |
|
920 |
* by configuring SVM and converting the root to the |
|
921 |
* dev_t of the mirrored root device. This dev_t conversion |
|
922 |
* only works because the underlying device doesn't change. |
|
923 |
*/ |
|
924 |
if (root_is_svm) { |
|
925 |
if (svm_rootconf()) { |
|
3446 | 926 |
panic("vfs_mountroot: cannot remount root"); |
0 | 927 |
} |
928 |
||
929 |
/* |
|
930 |
* mnttab should reflect the new root device |
|
931 |
*/ |
|
932 |
vfs_lock_wait(rootvfs); |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
933 |
vfs_setresource(rootvfs, rootfs.bo_name, 0); |
0 | 934 |
vfs_unlock(rootvfs); |
935 |
} |
|
936 |
#endif /* __sparc */ |
|
937 |
||
13832
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
938 |
if (strcmp(rootfs.bo_fstype, "zfs") != 0) { |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
939 |
/* |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
940 |
* Look up the root device via devfs so that a dv_node is |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
941 |
* created for it. The vnode is never VN_RELE()ed. |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
942 |
* We allocate more than MAXPATHLEN so that the |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
943 |
* buffer passed to i_ddi_prompath_to_devfspath() is |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
944 |
* exactly MAXPATHLEN (the function expects a buffer |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
945 |
* of that length). |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
946 |
*/ |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
947 |
plen = strlen("/devices"); |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
948 |
path = kmem_alloc(plen + MAXPATHLEN, KM_SLEEP); |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
949 |
(void) strcpy(path, "/devices"); |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
950 |
|
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
951 |
if (i_ddi_prompath_to_devfspath(rootfs.bo_name, path + plen) |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
952 |
!= DDI_SUCCESS || |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
953 |
lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, &rvp)) { |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
954 |
|
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
955 |
/* NUL terminate in case "path" has garbage */ |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
956 |
path[plen + MAXPATHLEN - 1] = '\0'; |
0 | 957 |
#ifdef DEBUG |
13832
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
958 |
cmn_err(CE_WARN, "!Cannot lookup root device: %s", |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
959 |
path); |
0 | 960 |
#endif |
13832
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
961 |
} |
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
962 |
kmem_free(path, plen + MAXPATHLEN); |
0 | 963 |
} |
13832
8e4bcbc31a4a
1126 date(1)'s usage message doesn't mention -R
Yuri Pankov <yuri.pankov@nexenta.com>
parents:
13178
diff
changeset
|
964 |
|
4863 | 965 |
vfs_mnttabvp_setup(); |
0 | 966 |
} |
967 |
||
968 |
/* |
|
6734 | 969 |
* Check to see if our "block device" is actually a file. If so, |
970 |
* automatically add a lofi device, and keep track of this fact. |
|
971 |
*/ |
|
972 |
static int |
|
973 |
lofi_add(const char *fsname, struct vfs *vfsp, |
|
974 |
mntopts_t *mntopts, struct mounta *uap) |
|
975 |
{ |
|
976 |
int fromspace = (uap->flags & MS_SYSSPACE) ? |
|
977 |
UIO_SYSSPACE : UIO_USERSPACE; |
|
978 |
struct lofi_ioctl *li = NULL; |
|
979 |
struct vnode *vp = NULL; |
|
980 |
struct pathname pn = { NULL }; |
|
981 |
ldi_ident_t ldi_id; |
|
982 |
ldi_handle_t ldi_hdl; |
|
6855 | 983 |
vfssw_t *vfssw; |
6734 | 984 |
int minor; |
985 |
int err = 0; |
|
986 |
||
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
987 |
if ((vfssw = vfs_getvfssw(fsname)) == NULL) |
6734 | 988 |
return (0); |
6855 | 989 |
|
990 |
if (!(vfssw->vsw_flag & VSW_CANLOFI)) { |
|
991 |
vfs_unrefvfssw(vfssw); |
|
6734 | 992 |
return (0); |
6855 | 993 |
} |
994 |
||
995 |
vfs_unrefvfssw(vfssw); |
|
996 |
vfssw = NULL; |
|
6734 | 997 |
|
998 |
if (pn_get(uap->spec, fromspace, &pn) != 0) |
|
999 |
return (0); |
|
1000 |
||
1001 |
if (lookupname(uap->spec, fromspace, FOLLOW, NULL, &vp) != 0) |
|
1002 |
goto out; |
|
1003 |
||
1004 |
if (vp->v_type != VREG) |
|
1005 |
goto out; |
|
1006 |
||
1007 |
/* OK, this is a lofi mount. */ |
|
1008 |
||
1009 |
if ((uap->flags & (MS_REMOUNT|MS_GLOBAL)) || |
|
1010 |
vfs_optionisset_nolock(mntopts, MNTOPT_SUID, NULL) || |
|
1011 |
vfs_optionisset_nolock(mntopts, MNTOPT_SETUID, NULL) || |
|
1012 |
vfs_optionisset_nolock(mntopts, MNTOPT_DEVICES, NULL)) { |
|
1013 |
err = EINVAL; |
|
1014 |
goto out; |
|
1015 |
} |
|
1016 |
||
1017 |
ldi_id = ldi_ident_from_anon(); |
|
1018 |
li = kmem_zalloc(sizeof (*li), KM_SLEEP); |
|
8081
cb8ad0d5637f
6743213 lofi ioctl filename should be MAXPATHLEN
Dina K Nimeh <Dina.Nimeh@Sun.Com>
parents:
7757
diff
changeset
|
1019 |
(void) strlcpy(li->li_filename, pn.pn_path, MAXPATHLEN); |
6734 | 1020 |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1021 |
err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred, |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1022 |
&ldi_hdl, ldi_id); |
6734 | 1023 |
|
1024 |
if (err) |
|
1025 |
goto out2; |
|
1026 |
||
1027 |
err = ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li, |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1028 |
FREAD | FWRITE | FKIOCTL, kcred, &minor); |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1029 |
|
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1030 |
(void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred); |
6734 | 1031 |
|
1032 |
if (!err) |
|
1033 |
vfsp->vfs_lofi_minor = minor; |
|
1034 |
||
1035 |
out2: |
|
1036 |
ldi_ident_release(ldi_id); |
|
1037 |
out: |
|
1038 |
if (li != NULL) |
|
1039 |
kmem_free(li, sizeof (*li)); |
|
1040 |
if (vp != NULL) |
|
1041 |
VN_RELE(vp); |
|
1042 |
pn_free(&pn); |
|
1043 |
return (err); |
|
1044 |
} |
|
1045 |
||
1046 |
static void |
|
1047 |
lofi_remove(struct vfs *vfsp) |
|
1048 |
{ |
|
1049 |
struct lofi_ioctl *li = NULL; |
|
1050 |
ldi_ident_t ldi_id; |
|
1051 |
ldi_handle_t ldi_hdl; |
|
1052 |
int err; |
|
1053 |
||
1054 |
if (vfsp->vfs_lofi_minor == 0) |
|
1055 |
return; |
|
1056 |
||
1057 |
ldi_id = ldi_ident_from_anon(); |
|
1058 |
||
1059 |
li = kmem_zalloc(sizeof (*li), KM_SLEEP); |
|
1060 |
li->li_minor = vfsp->vfs_lofi_minor; |
|
1061 |
li->li_cleanup = B_TRUE; |
|
1062 |
||
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1063 |
err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred, |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1064 |
&ldi_hdl, ldi_id); |
6734 | 1065 |
|
1066 |
if (err) |
|
1067 |
goto out; |
|
1068 |
||
1069 |
err = ldi_ioctl(ldi_hdl, LOFI_UNMAP_FILE_MINOR, (intptr_t)li, |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1070 |
FREAD | FWRITE | FKIOCTL, kcred, NULL); |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1071 |
|
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1072 |
(void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred); |
6734 | 1073 |
|
1074 |
if (!err) |
|
1075 |
vfsp->vfs_lofi_minor = 0; |
|
1076 |
||
1077 |
out: |
|
1078 |
ldi_ident_release(ldi_id); |
|
1079 |
if (li != NULL) |
|
1080 |
kmem_free(li, sizeof (*li)); |
|
1081 |
} |
|
1082 |
||
1083 |
/* |
|
0 | 1084 |
* Common mount code. Called from the system call entry point, from autofs, |
5302 | 1085 |
* nfsv4 trigger mounts, and from pxfs. |
0 | 1086 |
* |
1087 |
* Takes the effective file system type, mount arguments, the mount point |
|
1088 |
* vnode, flags specifying whether the mount is a remount and whether it |
|
1089 |
* should be entered into the vfs list, and credentials. Fills in its vfspp |
|
1090 |
* parameter with the mounted file system instance's vfs. |
|
1091 |
* |
|
1092 |
* Note that the effective file system type is specified as a string. It may |
|
1093 |
* be null, in which case it's determined from the mount arguments, and may |
|
1094 |
* differ from the type specified in the mount arguments; this is a hook to |
|
1095 |
* allow interposition when instantiating file system instances. |
|
1096 |
* |
|
1097 |
* The caller is responsible for releasing its own hold on the mount point |
|
1098 |
* vp (this routine does its own hold when necessary). |
|
1099 |
* Also note that for remounts, the mount point vp should be the vnode for |
|
1100 |
* the root of the file system rather than the vnode that the file system |
|
1101 |
* is mounted on top of. |
|
1102 |
*/ |
|
1103 |
int |
|
1104 |
domount(char *fsname, struct mounta *uap, vnode_t *vp, struct cred *credp, |
|
1105 |
struct vfs **vfspp) |
|
1106 |
{ |
|
1107 |
struct vfssw *vswp; |
|
1108 |
vfsops_t *vfsops; |
|
1109 |
struct vfs *vfsp; |
|
1110 |
struct vnode *bvp; |
|
1111 |
dev_t bdev = 0; |
|
1112 |
mntopts_t mnt_mntopts; |
|
1113 |
int error = 0; |
|
1114 |
int copyout_error = 0; |
|
1115 |
int ovflags; |
|
1116 |
char *opts = uap->optptr; |
|
1117 |
char *inargs = opts; |
|
1118 |
int optlen = uap->optlen; |
|
1119 |
int remount; |
|
1120 |
int rdonly; |
|
1121 |
int nbmand = 0; |
|
1122 |
int delmip = 0; |
|
1123 |
int addmip = 0; |
|
1124 |
int splice = ((uap->flags & MS_NOSPLICE) == 0); |
|
1125 |
int fromspace = (uap->flags & MS_SYSSPACE) ? |
|
3912 | 1126 |
UIO_SYSSPACE : UIO_USERSPACE; |
0 | 1127 |
char *resource = NULL, *mountpt = NULL; |
1128 |
refstr_t *oldresource, *oldmntpt; |
|
1129 |
struct pathname pn, rpn; |
|
1520 | 1130 |
vsk_anchor_t *vskap; |
6734 | 1131 |
char fstname[FSTYPSZ]; |
0 | 1132 |
|
1133 |
/* |
|
1134 |
* The v_flag value for the mount point vp is permanently set |
|
1135 |
* to VVFSLOCK so that no one bypasses the vn_vfs*locks routine |
|
1136 |
* for mount point locking. |
|
1137 |
*/ |
|
1138 |
mutex_enter(&vp->v_lock); |
|
1139 |
vp->v_flag |= VVFSLOCK; |
|
1140 |
mutex_exit(&vp->v_lock); |
|
1141 |
||
1142 |
mnt_mntopts.mo_count = 0; |
|
1143 |
/* |
|
1144 |
* Find the ops vector to use to invoke the file system-specific mount |
|
1145 |
* method. If the fsname argument is non-NULL, use it directly. |
|
1146 |
* Otherwise, dig the file system type information out of the mount |
|
1147 |
* arguments. |
|
1148 |
* |
|
1149 |
* A side effect is to hold the vfssw entry. |
|
1150 |
* |
|
1151 |
* Mount arguments can be specified in several ways, which are |
|
1152 |
* distinguished by flag bit settings. The preferred way is to set |
|
1153 |
* MS_OPTIONSTR, indicating an 8 argument mount with the file system |
|
1154 |
* type supplied as a character string and the last two arguments |
|
1155 |
* being a pointer to a character buffer and the size of the buffer. |
|
1156 |
* On entry, the buffer holds a null terminated list of options; on |
|
1157 |
* return, the string is the list of options the file system |
|
1158 |
* recognized. If MS_DATA is set arguments five and six point to a |
|
1159 |
* block of binary data which the file system interprets. |
|
1160 |
* A further wrinkle is that some callers don't set MS_FSS and MS_DATA |
|
1161 |
* consistently with these conventions. To handle them, we check to |
|
1162 |
* see whether the pointer to the file system name has a numeric value |
|
1163 |
* less than 256. If so, we treat it as an index. |
|
1164 |
*/ |
|
1165 |
if (fsname != NULL) { |
|
1166 |
if ((vswp = vfs_getvfssw(fsname)) == NULL) { |
|
1167 |
return (EINVAL); |
|
1168 |
} |
|
1169 |
} else if (uap->flags & (MS_OPTIONSTR | MS_DATA | MS_FSS)) { |
|
1170 |
size_t n; |
|
1171 |
uint_t fstype; |
|
6734 | 1172 |
|
1173 |
fsname = fstname; |
|
0 | 1174 |
|
1175 |
if ((fstype = (uintptr_t)uap->fstype) < 256) { |
|
1176 |
RLOCK_VFSSW(); |
|
1177 |
if (fstype == 0 || fstype >= nfstype || |
|
1178 |
!ALLOCATED_VFSSW(&vfssw[fstype])) { |
|
1179 |
RUNLOCK_VFSSW(); |
|
1180 |
return (EINVAL); |
|
1181 |
} |
|
6734 | 1182 |
(void) strcpy(fsname, vfssw[fstype].vsw_name); |
0 | 1183 |
RUNLOCK_VFSSW(); |
6734 | 1184 |
if ((vswp = vfs_getvfssw(fsname)) == NULL) |
0 | 1185 |
return (EINVAL); |
1186 |
} else { |
|
1187 |
/* |
|
1188 |
* Handle either kernel or user address space. |
|
1189 |
*/ |
|
1190 |
if (uap->flags & MS_SYSSPACE) { |
|
6734 | 1191 |
error = copystr(uap->fstype, fsname, |
0 | 1192 |
FSTYPSZ, &n); |
1193 |
} else { |
|
6734 | 1194 |
error = copyinstr(uap->fstype, fsname, |
0 | 1195 |
FSTYPSZ, &n); |
1196 |
} |
|
1197 |
if (error) { |
|
1198 |
if (error == ENAMETOOLONG) |
|
1199 |
return (EINVAL); |
|
1200 |
return (error); |
|
1201 |
} |
|
6734 | 1202 |
if ((vswp = vfs_getvfssw(fsname)) == NULL) |
0 | 1203 |
return (EINVAL); |
1204 |
} |
|
1205 |
} else { |
|
1206 |
if ((vswp = vfs_getvfsswbyvfsops(vfs_getops(rootvfs))) == NULL) |
|
1207 |
return (EINVAL); |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1208 |
fsname = vswp->vsw_name; |
0 | 1209 |
} |
1210 |
if (!VFS_INSTALLED(vswp)) |
|
1211 |
return (EINVAL); |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1212 |
|
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1213 |
if ((error = secpolicy_fs_allowed_mount(fsname)) != 0) { |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1214 |
vfs_unrefvfssw(vswp); |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1215 |
return (error); |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1216 |
} |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
1217 |
|
0 | 1218 |
vfsops = &vswp->vsw_vfsops; |
1219 |
||
1220 |
vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts); |
|
1221 |
/* |
|
1222 |
* Fetch mount options and parse them for generic vfs options |
|
1223 |
*/ |
|
1224 |
if (uap->flags & MS_OPTIONSTR) { |
|
1225 |
/* |
|
1226 |
* Limit the buffer size |
|
1227 |
*/ |
|
1228 |
if (optlen < 0 || optlen > MAX_MNTOPT_STR) { |
|
1229 |
error = EINVAL; |
|
1230 |
goto errout; |
|
1231 |
} |
|
1232 |
if ((uap->flags & MS_SYSSPACE) == 0) { |
|
1233 |
inargs = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP); |
|
1234 |
inargs[0] = '\0'; |
|
1235 |
if (optlen) { |
|
1236 |
error = copyinstr(opts, inargs, (size_t)optlen, |
|
3912 | 1237 |
NULL); |
0 | 1238 |
if (error) { |
1239 |
goto errout; |
|
1240 |
} |
|
1241 |
} |
|
1242 |
} |
|
1243 |
vfs_parsemntopts(&mnt_mntopts, inargs, 0); |
|
1244 |
} |
|
1245 |
/* |
|
1246 |
* Flag bits override the options string. |
|
1247 |
*/ |
|
1248 |
if (uap->flags & MS_REMOUNT) |
|
1249 |
vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_REMOUNT, NULL, 0, 0); |
|
1250 |
if (uap->flags & MS_RDONLY) |
|
1251 |
vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_RO, NULL, 0, 0); |
|
1252 |
if (uap->flags & MS_NOSUID) |
|
1253 |
vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0); |
|
1254 |
||
1255 |
/* |
|
1256 |
* Check if this is a remount; must be set in the option string and |
|
1257 |
* the file system must support a remount option. |
|
1258 |
*/ |
|
1259 |
if (remount = vfs_optionisset_nolock(&mnt_mntopts, |
|
1260 |
MNTOPT_REMOUNT, NULL)) { |
|
1261 |
if (!(vswp->vsw_flag & VSW_CANREMOUNT)) { |
|
1262 |
error = ENOTSUP; |
|
1263 |
goto errout; |
|
1264 |
} |
|
1265 |
uap->flags |= MS_REMOUNT; |
|
1266 |
} |
|
1267 |
||
1268 |
/* |
|
1269 |
* uap->flags and vfs_optionisset() should agree. |
|
1270 |
*/ |
|
1271 |
if (rdonly = vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_RO, NULL)) { |
|
1272 |
uap->flags |= MS_RDONLY; |
|
1273 |
} |
|
1274 |
if (vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL)) { |
|
1275 |
uap->flags |= MS_NOSUID; |
|
1276 |
} |
|
1277 |
nbmand = vfs_optionisset_nolock(&mnt_mntopts, MNTOPT_NBMAND, NULL); |
|
1278 |
ASSERT(splice || !remount); |
|
1279 |
/* |
|
1280 |
* If we are splicing the fs into the namespace, |
|
1281 |
* perform mount point checks. |
|
1282 |
* |
|
1283 |
* We want to resolve the path for the mount point to eliminate |
|
1284 |
* '.' and ".." and symlinks in mount points; we can't do the |
|
1285 |
* same for the resource string, since it would turn |
|
1286 |
* "/dev/dsk/c0t0d0s0" into "/devices/pci@...". We need to do |
|
1287 |
* this before grabbing vn_vfswlock(), because otherwise we |
|
1288 |
* would deadlock with lookuppn(). |
|
1289 |
*/ |
|
1290 |
if (splice) { |
|
1291 |
ASSERT(vp->v_count > 0); |
|
1292 |
||
1293 |
/* |
|
1294 |
* Pick up mount point and device from appropriate space. |
|
1295 |
*/ |
|
1296 |
if (pn_get(uap->spec, fromspace, &pn) == 0) { |
|
1297 |
resource = kmem_alloc(pn.pn_pathlen + 1, |
|
1298 |
KM_SLEEP); |
|
1299 |
(void) strcpy(resource, pn.pn_path); |
|
1300 |
pn_free(&pn); |
|
1301 |
} |
|
1302 |
/* |
|
1303 |
* Do a lookupname prior to taking the |
|
1304 |
* writelock. Mark this as completed if |
|
1305 |
* successful for later cleanup and addition to |
|
1306 |
* the mount in progress table. |
|
1307 |
*/ |
|
1308 |
if ((uap->flags & MS_GLOBAL) == 0 && |
|
1309 |
lookupname(uap->spec, fromspace, |
|
3912 | 1310 |
FOLLOW, NULL, &bvp) == 0) { |
0 | 1311 |
addmip = 1; |
1312 |
} |
|
1313 |
||
1314 |
if ((error = pn_get(uap->dir, fromspace, &pn)) == 0) { |
|
1315 |
pathname_t *pnp; |
|
1316 |
||
1317 |
if (*pn.pn_path != '/') { |
|
1318 |
error = EINVAL; |
|
1319 |
pn_free(&pn); |
|
1320 |
goto errout; |
|
1321 |
} |
|
1322 |
pn_alloc(&rpn); |
|
1323 |
/* |
|
1324 |
* Kludge to prevent autofs from deadlocking with |
|
1325 |
* itself when it calls domount(). |
|
1326 |
* |
|
1327 |
* If autofs is calling, it is because it is doing |
|
1328 |
* (autofs) mounts in the process of an NFS mount. A |
|
1329 |
* lookuppn() here would cause us to block waiting for |
|
1330 |
* said NFS mount to complete, which can't since this |
|
1331 |
* is the thread that was supposed to doing it. |
|
1332 |
*/ |
|
1333 |
if (fromspace == UIO_USERSPACE) { |
|
1334 |
if ((error = lookuppn(&pn, &rpn, FOLLOW, NULL, |
|
1335 |
NULL)) == 0) { |
|
1336 |
pnp = &rpn; |
|
1337 |
} else { |
|
1338 |
/* |
|
1339 |
* The file disappeared or otherwise |
|
1340 |
* became inaccessible since we opened |
|
1341 |
* it; might as well fail the mount |
|
1342 |
* since the mount point is no longer |
|
1343 |
* accessible. |
|
1344 |
*/ |
|
1345 |
pn_free(&rpn); |
|
1346 |
pn_free(&pn); |
|
1347 |
goto errout; |
|
1348 |
} |
|
1349 |
} else { |
|
1350 |
pnp = &pn; |
|
1351 |
} |
|
1352 |
mountpt = kmem_alloc(pnp->pn_pathlen + 1, KM_SLEEP); |
|
1353 |
(void) strcpy(mountpt, pnp->pn_path); |
|
1354 |
||
1355 |
/* |
|
1356 |
* If the addition of the zone's rootpath |
|
1357 |
* would push us over a total path length |
|
1358 |
* of MAXPATHLEN, we fail the mount with |
|
1359 |
* ENAMETOOLONG, which is what we would have |
|
1360 |
* gotten if we were trying to perform the same |
|
1361 |
* mount in the global zone. |
|
1362 |
* |
|
1363 |
* strlen() doesn't count the trailing |
|
1364 |
* '\0', but zone_rootpathlen counts both a |
|
1365 |
* trailing '/' and the terminating '\0'. |
|
1366 |
*/ |
|
1367 |
if ((curproc->p_zone->zone_rootpathlen - 1 + |
|
1368 |
strlen(mountpt)) > MAXPATHLEN || |
|
1369 |
(resource != NULL && |
|
1370 |
(curproc->p_zone->zone_rootpathlen - 1 + |
|
1371 |
strlen(resource)) > MAXPATHLEN)) { |
|
1372 |
error = ENAMETOOLONG; |
|
1373 |
} |
|
1374 |
||
1375 |
pn_free(&rpn); |
|
1376 |
pn_free(&pn); |
|
1377 |
} |
|
1378 |
||
1379 |
if (error) |
|
1380 |
goto errout; |
|
1381 |
||
1382 |
/* |
|
1383 |
* Prevent path name resolution from proceeding past |
|
1384 |
* the mount point. |
|
1385 |
*/ |
|
1386 |
if (vn_vfswlock(vp) != 0) { |
|
1387 |
error = EBUSY; |
|
1388 |
goto errout; |
|
1389 |
} |
|
1390 |
||
1391 |
/* |
|
1392 |
* Verify that it's legitimate to establish a mount on |
|
1393 |
* the prospective mount point. |
|
1394 |
*/ |
|
1395 |
if (vn_mountedvfs(vp) != NULL) { |
|
1396 |
/* |
|
1397 |
* The mount point lock was obtained after some |
|
1398 |
* other thread raced through and established a mount. |
|
1399 |
*/ |
|
1400 |
vn_vfsunlock(vp); |
|
1401 |
error = EBUSY; |
|
1402 |
goto errout; |
|
1403 |
} |
|
1404 |
if (vp->v_flag & VNOMOUNT) { |
|
1405 |
vn_vfsunlock(vp); |
|
1406 |
error = EINVAL; |
|
1407 |
goto errout; |
|
1408 |
} |
|
1409 |
} |
|
1410 |
if ((uap->flags & (MS_DATA | MS_OPTIONSTR)) == 0) { |
|
1411 |
uap->dataptr = NULL; |
|
1412 |
uap->datalen = 0; |
|
1413 |
} |
|
1414 |
||
1415 |
/* |
|
1416 |
* If this is a remount, we don't want to create a new VFS. |
|
1417 |
* Instead, we pass the existing one with a remount flag. |
|
1418 |
*/ |
|
1419 |
if (remount) { |
|
1420 |
/* |
|
1421 |
* Confirm that the mount point is the root vnode of the |
|
1422 |
* file system that is being remounted. |
|
1423 |
* This can happen if the user specifies a different |
|
1424 |
* mount point directory pathname in the (re)mount command. |
|
1425 |
* |
|
1426 |
* Code below can only be reached if splice is true, so it's |
|
1427 |
* safe to do vn_vfsunlock() here. |
|
1428 |
*/ |
|
1429 |
if ((vp->v_flag & VROOT) == 0) { |
|
1430 |
vn_vfsunlock(vp); |
|
1431 |
error = ENOENT; |
|
1432 |
goto errout; |
|
1433 |
} |
|
1434 |
/* |
|
1435 |
* Disallow making file systems read-only unless file system |
|
1436 |
* explicitly allows it in its vfssw. Ignore other flags. |
|
1437 |
*/ |
|
1438 |
if (rdonly && vn_is_readonly(vp) == 0 && |
|
1439 |
(vswp->vsw_flag & VSW_CANRWRO) == 0) { |
|
1440 |
vn_vfsunlock(vp); |
|
1441 |
error = EINVAL; |
|
1442 |
goto errout; |
|
1443 |
} |
|
1444 |
/* |
|
5331 | 1445 |
* Disallow changing the NBMAND disposition of the file |
1446 |
* system on remounts. |
|
0 | 1447 |
*/ |
1448 |
if ((nbmand && ((vp->v_vfsp->vfs_flag & VFS_NBMAND) == 0)) || |
|
1449 |
(!nbmand && (vp->v_vfsp->vfs_flag & VFS_NBMAND))) { |
|
5331 | 1450 |
vn_vfsunlock(vp); |
1451 |
error = EINVAL; |
|
1452 |
goto errout; |
|
0 | 1453 |
} |
1454 |
vfsp = vp->v_vfsp; |
|
1455 |
ovflags = vfsp->vfs_flag; |
|
1456 |
vfsp->vfs_flag |= VFS_REMOUNT; |
|
1457 |
vfsp->vfs_flag &= ~VFS_RDONLY; |
|
1458 |
} else { |
|
5331 | 1459 |
vfsp = vfs_alloc(KM_SLEEP); |
0 | 1460 |
VFS_INIT(vfsp, vfsops, NULL); |
1461 |
} |
|
1462 |
||
1463 |
VFS_HOLD(vfsp); |
|
1464 |
||
6734 | 1465 |
if ((error = lofi_add(fsname, vfsp, &mnt_mntopts, uap)) != 0) { |
1466 |
if (!remount) { |
|
1467 |
if (splice) |
|
1468 |
vn_vfsunlock(vp); |
|
1469 |
vfs_free(vfsp); |
|
1470 |
} else { |
|
1471 |
vn_vfsunlock(vp); |
|
1472 |
VFS_RELE(vfsp); |
|
1473 |
} |
|
1474 |
goto errout; |
|
1475 |
} |
|
1476 |
||
1477 |
/* |
|
1478 |
* PRIV_SYS_MOUNT doesn't mean you can become root. |
|
1479 |
*/ |
|
1480 |
if (vfsp->vfs_lofi_minor != 0) { |
|
1481 |
uap->flags |= MS_NOSUID; |
|
1482 |
vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0); |
|
1483 |
} |
|
1484 |
||
0 | 1485 |
/* |
1486 |
* The vfs_reflock is not used anymore the code below explicitly |
|
1487 |
* holds it preventing others accesing it directly. |
|
1488 |
*/ |
|
1489 |
if ((sema_tryp(&vfsp->vfs_reflock) == 0) && |
|
1490 |
!(vfsp->vfs_flag & VFS_REMOUNT)) |
|
1491 |
cmn_err(CE_WARN, |
|
3446 | 1492 |
"mount type %s couldn't get vfs_reflock", vswp->vsw_name); |
0 | 1493 |
|
1494 |
/* |
|
1495 |
* Lock the vfs. If this is a remount we want to avoid spurious umount |
|
1496 |
* failures that happen as a side-effect of fsflush() and other mount |
|
1497 |
* and unmount operations that might be going on simultaneously and |
|
1498 |
* may have locked the vfs currently. To not return EBUSY immediately |
|
1499 |
* here we use vfs_lock_wait() instead vfs_lock() for the remount case. |
|
1500 |
*/ |
|
1501 |
if (!remount) { |
|
1502 |
if (error = vfs_lock(vfsp)) { |
|
1503 |
vfsp->vfs_flag = ovflags; |
|
6734 | 1504 |
|
1505 |
lofi_remove(vfsp); |
|
1506 |
||
0 | 1507 |
if (splice) |
1508 |
vn_vfsunlock(vp); |
|
5331 | 1509 |
vfs_free(vfsp); |
0 | 1510 |
goto errout; |
1511 |
} |
|
1512 |
} else { |
|
1513 |
vfs_lock_wait(vfsp); |
|
1514 |
} |
|
1515 |
||
1516 |
/* |
|
1517 |
* Add device to mount in progress table, global mounts require special |
|
1518 |
* handling. It is possible that we have already done the lookupname |
|
1519 |
* on a spliced, non-global fs. If so, we don't want to do it again |
|
1520 |
* since we cannot do a lookupname after taking the |
|
1521 |
* wlock above. This case is for a non-spliced, non-global filesystem. |
|
1522 |
*/ |
|
1523 |
if (!addmip) { |
|
3912 | 1524 |
if ((uap->flags & MS_GLOBAL) == 0 && |
1525 |
lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp) == 0) { |
|
0 | 1526 |
addmip = 1; |
1527 |
} |
|
1528 |
} |
|
1529 |
||
1530 |
if (addmip) { |
|
6734 | 1531 |
vnode_t *lvp = NULL; |
1532 |
||
1533 |
error = vfs_get_lofi(vfsp, &lvp); |
|
1534 |
if (error > 0) { |
|
1535 |
lofi_remove(vfsp); |
|
1536 |
||
1537 |
if (splice) |
|
1538 |
vn_vfsunlock(vp); |
|
1539 |
vfs_unlock(vfsp); |
|
1540 |
||
1541 |
if (remount) { |
|
1542 |
VFS_RELE(vfsp); |
|
1543 |
} else { |
|
1544 |
vfs_free(vfsp); |
|
1545 |
} |
|
1546 |
||
1547 |
goto errout; |
|
1548 |
} else if (error == -1) { |
|
1549 |
bdev = bvp->v_rdev; |
|
1550 |
VN_RELE(bvp); |
|
1551 |
} else { |
|
1552 |
bdev = lvp->v_rdev; |
|
1553 |
VN_RELE(lvp); |
|
1554 |
VN_RELE(bvp); |
|
1555 |
} |
|
1556 |
||
0 | 1557 |
vfs_addmip(bdev, vfsp); |
1558 |
addmip = 0; |
|
1559 |
delmip = 1; |
|
1560 |
} |
|
1561 |
/* |
|
1562 |
* Invalidate cached entry for the mount point. |
|
1563 |
*/ |
|
1564 |
if (splice) |
|
1565 |
dnlc_purge_vp(vp); |
|
1566 |
||
1567 |
/* |
|
1568 |
* If have an option string but the filesystem doesn't supply a |
|
1569 |
* prototype options table, create a table with the global |
|
1570 |
* options and sufficient room to accept all the options in the |
|
1571 |
* string. Then parse the passed in option string |
|
1572 |
* accepting all the options in the string. This gives us an |
|
1573 |
* option table with all the proper cancel properties for the |
|
1574 |
* global options. |
|
1575 |
* |
|
1576 |
* Filesystems that supply a prototype options table are handled |
|
1577 |
* earlier in this function. |
|
1578 |
*/ |
|
1579 |
if (uap->flags & MS_OPTIONSTR) { |
|
1580 |
if (!(vswp->vsw_flag & VSW_HASPROTO)) { |
|
1581 |
mntopts_t tmp_mntopts; |
|
1582 |
||
1583 |
tmp_mntopts.mo_count = 0; |
|
1584 |
vfs_createopttbl_extend(&tmp_mntopts, inargs, |
|
1585 |
&mnt_mntopts); |
|
1586 |
vfs_parsemntopts(&tmp_mntopts, inargs, 1); |
|
1587 |
vfs_swapopttbl_nolock(&mnt_mntopts, &tmp_mntopts); |
|
1588 |
vfs_freeopttbl(&tmp_mntopts); |
|
1589 |
} |
|
1590 |
} |
|
1591 |
||
1592 |
/* |
|
1593 |
* Serialize with zone creations. |
|
1594 |
*/ |
|
1595 |
mount_in_progress(); |
|
1596 |
/* |
|
1597 |
* Instantiate (or reinstantiate) the file system. If appropriate, |
|
1598 |
* splice it into the file system name space. |
|
1599 |
* |
|
1600 |
* We want VFS_MOUNT() to be able to override the vfs_resource |
|
1601 |
* string if necessary (ie, mntfs), and also for a remount to |
|
1602 |
* change the same (necessary when remounting '/' during boot). |
|
1603 |
* So we set up vfs_mntpt and vfs_resource to what we think they |
|
1604 |
* should be, then hand off control to VFS_MOUNT() which can |
|
1605 |
* override this. |
|
1606 |
* |
|
1607 |
* For safety's sake, when changing vfs_resource or vfs_mntpt of |
|
1608 |
* a vfs which is on the vfs list (i.e. during a remount), we must |
|
1609 |
* never set those fields to NULL. Several bits of code make |
|
1610 |
* assumptions that the fields are always valid. |
|
1611 |
*/ |
|
1612 |
vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts); |
|
1613 |
if (remount) { |
|
1614 |
if ((oldresource = vfsp->vfs_resource) != NULL) |
|
1615 |
refstr_hold(oldresource); |
|
1616 |
if ((oldmntpt = vfsp->vfs_mntpt) != NULL) |
|
1617 |
refstr_hold(oldmntpt); |
|
1618 |
} |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1619 |
vfs_setresource(vfsp, resource, 0); |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1620 |
vfs_setmntpoint(vfsp, mountpt, 0); |
0 | 1621 |
|
4863 | 1622 |
/* |
1623 |
* going to mount on this vnode, so notify. |
|
1624 |
*/ |
|
5331 | 1625 |
vnevent_mountedover(vp, NULL); |
0 | 1626 |
error = VFS_MOUNT(vfsp, vp, uap, credp); |
1627 |
||
1628 |
if (uap->flags & MS_RDONLY) |
|
1629 |
vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0); |
|
1630 |
if (uap->flags & MS_NOSUID) |
|
1631 |
vfs_setmntopt(vfsp, MNTOPT_NOSUID, NULL, 0); |
|
1632 |
if (uap->flags & MS_GLOBAL) |
|
1633 |
vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0); |
|
1634 |
||
1635 |
if (error) { |
|
6734 | 1636 |
lofi_remove(vfsp); |
1637 |
||
0 | 1638 |
if (remount) { |
1639 |
/* put back pre-remount options */ |
|
1640 |
vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts); |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1641 |
vfs_setmntpoint(vfsp, refstr_value(oldmntpt), |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1642 |
VFSSP_VERBATIM); |
0 | 1643 |
if (oldmntpt) |
1644 |
refstr_rele(oldmntpt); |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1645 |
vfs_setresource(vfsp, refstr_value(oldresource), |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1646 |
VFSSP_VERBATIM); |
0 | 1647 |
if (oldresource) |
1648 |
refstr_rele(oldresource); |
|
1649 |
vfsp->vfs_flag = ovflags; |
|
1650 |
vfs_unlock(vfsp); |
|
1651 |
VFS_RELE(vfsp); |
|
1652 |
} else { |
|
1653 |
vfs_unlock(vfsp); |
|
1654 |
vfs_freemnttab(vfsp); |
|
5331 | 1655 |
vfs_free(vfsp); |
0 | 1656 |
} |
1657 |
} else { |
|
1658 |
/* |
|
1659 |
* Set the mount time to now |
|
1660 |
*/ |
|
1661 |
vfsp->vfs_mtime = ddi_get_time(); |
|
1662 |
if (remount) { |
|
1663 |
vfsp->vfs_flag &= ~VFS_REMOUNT; |
|
1664 |
if (oldresource) |
|
1665 |
refstr_rele(oldresource); |
|
1666 |
if (oldmntpt) |
|
1667 |
refstr_rele(oldmntpt); |
|
1668 |
} else if (splice) { |
|
1669 |
/* |
|
1670 |
* Link vfsp into the name space at the mount |
|
1671 |
* point. Vfs_add() is responsible for |
|
1672 |
* holding the mount point which will be |
|
1673 |
* released when vfs_remove() is called. |
|
1674 |
*/ |
|
1675 |
vfs_add(vp, vfsp, uap->flags); |
|
1676 |
} else { |
|
1677 |
/* |
|
1678 |
* Hold the reference to file system which is |
|
1679 |
* not linked into the name space. |
|
1680 |
*/ |
|
1681 |
vfsp->vfs_zone = NULL; |
|
1682 |
VFS_HOLD(vfsp); |
|
1683 |
vfsp->vfs_vnodecovered = NULL; |
|
1684 |
} |
|
1685 |
/* |
|
1686 |
* Set flags for global options encountered |
|
1687 |
*/ |
|
1688 |
if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) |
|
1689 |
vfsp->vfs_flag |= VFS_RDONLY; |
|
1690 |
else |
|
1691 |
vfsp->vfs_flag &= ~VFS_RDONLY; |
|
1692 |
if (vfs_optionisset(vfsp, MNTOPT_NOSUID, NULL)) { |
|
1693 |
vfsp->vfs_flag |= (VFS_NOSETUID|VFS_NODEVICES); |
|
1694 |
} else { |
|
1695 |
if (vfs_optionisset(vfsp, MNTOPT_NODEVICES, NULL)) |
|
1696 |
vfsp->vfs_flag |= VFS_NODEVICES; |
|
1697 |
else |
|
1698 |
vfsp->vfs_flag &= ~VFS_NODEVICES; |
|
1699 |
if (vfs_optionisset(vfsp, MNTOPT_NOSETUID, NULL)) |
|
1700 |
vfsp->vfs_flag |= VFS_NOSETUID; |
|
1701 |
else |
|
1702 |
vfsp->vfs_flag &= ~VFS_NOSETUID; |
|
1703 |
} |
|
1704 |
if (vfs_optionisset(vfsp, MNTOPT_NBMAND, NULL)) |
|
1705 |
vfsp->vfs_flag |= VFS_NBMAND; |
|
1706 |
else |
|
1707 |
vfsp->vfs_flag &= ~VFS_NBMAND; |
|
1708 |
||
1709 |
if (vfs_optionisset(vfsp, MNTOPT_XATTR, NULL)) |
|
1710 |
vfsp->vfs_flag |= VFS_XATTR; |
|
1711 |
else |
|
1712 |
vfsp->vfs_flag &= ~VFS_XATTR; |
|
1713 |
||
1714 |
if (vfs_optionisset(vfsp, MNTOPT_NOEXEC, NULL)) |
|
1715 |
vfsp->vfs_flag |= VFS_NOEXEC; |
|
1716 |
else |
|
1717 |
vfsp->vfs_flag &= ~VFS_NOEXEC; |
|
1718 |
||
1719 |
/* |
|
1720 |
* Now construct the output option string of options |
|
1721 |
* we recognized. |
|
1722 |
*/ |
|
1723 |
if (uap->flags & MS_OPTIONSTR) { |
|
1724 |
vfs_list_read_lock(); |
|
1725 |
copyout_error = vfs_buildoptionstr( |
|
3912 | 1726 |
&vfsp->vfs_mntopts, inargs, optlen); |
0 | 1727 |
vfs_list_unlock(); |
1728 |
if (copyout_error == 0 && |
|
1729 |
(uap->flags & MS_SYSSPACE) == 0) { |
|
1730 |
copyout_error = copyoutstr(inargs, opts, |
|
1731 |
optlen, NULL); |
|
1732 |
} |
|
1733 |
} |
|
1488 | 1734 |
|
1520 | 1735 |
/* |
1736 |
* If this isn't a remount, set up the vopstats before |
|
1678
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1737 |
* anyone can touch this. We only allow spliced file |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1738 |
* systems (file systems which are in the namespace) to |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1739 |
* have the VFS_STATS flag set. |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1740 |
* NOTE: PxFS mounts the underlying file system with |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1741 |
* MS_NOSPLICE set and copies those vfs_flags to its private |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1742 |
* vfs structure. As a result, PxFS should never have |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1743 |
* the VFS_STATS flag or else we might access the vfs |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1744 |
* statistics-related fields prior to them being |
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1745 |
* properly initialized. |
1520 | 1746 |
*/ |
1678
cd336ddf9a1c
6397933 fs node paniced while mounting global filesystem (/global/.devices/node@x)
rsb
parents:
1520
diff
changeset
|
1747 |
if (!remount && (vswp->vsw_flag & VSW_STATS) && splice) { |
1520 | 1748 |
initialize_vopstats(&vfsp->vfs_vopstats); |
1749 |
/* |
|
1750 |
* We need to set vfs_vskap to NULL because there's |
|
1751 |
* a chance it won't be set below. This is checked |
|
1752 |
* in teardown_vopstats() so we can't have garbage. |
|
1753 |
*/ |
|
1754 |
vfsp->vfs_vskap = NULL; |
|
1488 | 1755 |
vfsp->vfs_flag |= VFS_STATS; |
1520 | 1756 |
vfsp->vfs_fstypevsp = get_fstype_vopstats(vfsp, vswp); |
1488 | 1757 |
} |
1758 |
||
4321
a8930ec16e52
PSARC 2007/064 Unified POSIX and Windows Credentials for Solaris
casper
parents:
3957
diff
changeset
|
1759 |
if (vswp->vsw_flag & VSW_XID) |
a8930ec16e52
PSARC 2007/064 Unified POSIX and Windows Credentials for Solaris
casper
parents:
3957
diff
changeset
|
1760 |
vfsp->vfs_flag |= VFS_XID; |
a8930ec16e52
PSARC 2007/064 Unified POSIX and Windows Credentials for Solaris
casper
parents:
3957
diff
changeset
|
1761 |
|
0 | 1762 |
vfs_unlock(vfsp); |
1763 |
} |
|
1764 |
mount_completed(); |
|
1765 |
if (splice) |
|
1766 |
vn_vfsunlock(vp); |
|
1767 |
||
1768 |
if ((error == 0) && (copyout_error == 0)) { |
|
1520 | 1769 |
if (!remount) { |
1770 |
/* |
|
1771 |
* Don't call get_vskstat_anchor() while holding |
|
1772 |
* locks since it allocates memory and calls |
|
1773 |
* VFS_STATVFS(). For NFS, the latter can generate |
|
1774 |
* an over-the-wire call. |
|
1775 |
*/ |
|
1776 |
vskap = get_vskstat_anchor(vfsp); |
|
1777 |
/* Only take the lock if we have something to do */ |
|
1778 |
if (vskap != NULL) { |
|
1779 |
vfs_lock_wait(vfsp); |
|
1780 |
if (vfsp->vfs_flag & VFS_STATS) { |
|
1781 |
vfsp->vfs_vskap = vskap; |
|
1782 |
} |
|
1783 |
vfs_unlock(vfsp); |
|
1784 |
} |
|
1785 |
} |
|
1488 | 1786 |
/* Return vfsp to caller. */ |
0 | 1787 |
*vfspp = vfsp; |
1788 |
} |
|
1789 |
errout: |
|
1790 |
vfs_freeopttbl(&mnt_mntopts); |
|
1791 |
if (resource != NULL) |
|
1792 |
kmem_free(resource, strlen(resource) + 1); |
|
1793 |
if (mountpt != NULL) |
|
1794 |
kmem_free(mountpt, strlen(mountpt) + 1); |
|
1795 |
/* |
|
1796 |
* It is possible we errored prior to adding to mount in progress |
|
1797 |
* table. Must free vnode we acquired with successful lookupname. |
|
1798 |
*/ |
|
1799 |
if (addmip) |
|
1800 |
VN_RELE(bvp); |
|
1801 |
if (delmip) |
|
1802 |
vfs_delmip(vfsp); |
|
1803 |
ASSERT(vswp != NULL); |
|
1804 |
vfs_unrefvfssw(vswp); |
|
1805 |
if (inargs != opts) |
|
1806 |
kmem_free(inargs, MAX_MNTOPT_STR); |
|
1807 |
if (copyout_error) { |
|
6734 | 1808 |
lofi_remove(vfsp); |
0 | 1809 |
VFS_RELE(vfsp); |
1810 |
error = copyout_error; |
|
1811 |
} |
|
1812 |
return (error); |
|
1813 |
} |
|
1814 |
||
1815 |
static void |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1816 |
vfs_setpath( |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1817 |
struct vfs *vfsp, /* vfs being updated */ |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1818 |
refstr_t **refp, /* Ref-count string to contain the new path */ |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1819 |
const char *newpath, /* Path to add to refp (above) */ |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1820 |
uint32_t flag) /* flag */ |
0 | 1821 |
{ |
1822 |
size_t len; |
|
1823 |
refstr_t *ref; |
|
1824 |
zone_t *zone = curproc->p_zone; |
|
1825 |
char *sp; |
|
1826 |
int have_list_lock = 0; |
|
1827 |
||
1828 |
ASSERT(!VFS_ON_LIST(vfsp) || vfs_lock_held(vfsp)); |
|
1829 |
||
1830 |
/* |
|
1831 |
* New path must be less than MAXPATHLEN because mntfs |
|
1832 |
* will only display up to MAXPATHLEN bytes. This is currently |
|
1833 |
* safe, because domount() uses pn_get(), and other callers |
|
1834 |
* similarly cap the size to fewer than MAXPATHLEN bytes. |
|
1835 |
*/ |
|
1836 |
||
1837 |
ASSERT(strlen(newpath) < MAXPATHLEN); |
|
1838 |
||
1839 |
/* mntfs requires consistency while vfs list lock is held */ |
|
1840 |
||
1841 |
if (VFS_ON_LIST(vfsp)) { |
|
1842 |
have_list_lock = 1; |
|
1843 |
vfs_list_lock(); |
|
1844 |
} |
|
1845 |
||
1846 |
if (*refp != NULL) |
|
1847 |
refstr_rele(*refp); |
|
1848 |
||
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1849 |
/* |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1850 |
* If we are in a non-global zone then we prefix the supplied path, |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1851 |
* newpath, with the zone's root path, with two exceptions. The first |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1852 |
* is where we have been explicitly directed to avoid doing so; this |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1853 |
* will be the case following a failed remount, where the path supplied |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1854 |
* will be a saved version which must now be restored. The second |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1855 |
* exception is where newpath is not a pathname but a descriptive name, |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1856 |
* e.g. "procfs". |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1857 |
*/ |
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1858 |
if (zone == global_zone || (flag & VFSSP_VERBATIM) || *newpath != '/') { |
0 | 1859 |
ref = refstr_alloc(newpath); |
1860 |
goto out; |
|
1861 |
} |
|
1862 |
||
1863 |
/* |
|
1864 |
* Truncate the trailing '/' in the zoneroot, and merge |
|
1865 |
* in the zone's rootpath with the "newpath" (resource |
|
1866 |
* or mountpoint) passed in. |
|
1867 |
* |
|
1868 |
* The size of the required buffer is thus the size of |
|
1869 |
* the buffer required for the passed-in newpath |
|
1870 |
* (strlen(newpath) + 1), plus the size of the buffer |
|
1871 |
* required to hold zone_rootpath (zone_rootpathlen) |
|
1872 |
* minus one for one of the now-superfluous NUL |
|
1873 |
* terminations, minus one for the trailing '/'. |
|
1874 |
* |
|
1875 |
* That gives us: |
|
1876 |
* |
|
1877 |
* (strlen(newpath) + 1) + zone_rootpathlen - 1 - 1 |
|
1878 |
* |
|
1879 |
* Which is what we have below. |
|
1880 |
*/ |
|
1881 |
||
1882 |
len = strlen(newpath) + zone->zone_rootpathlen - 1; |
|
1883 |
sp = kmem_alloc(len, KM_SLEEP); |
|
1884 |
||
1885 |
/* |
|
1886 |
* Copy everything including the trailing slash, which |
|
1887 |
* we then overwrite with the NUL character. |
|
1888 |
*/ |
|
1889 |
||
1890 |
(void) strcpy(sp, zone->zone_rootpath); |
|
1891 |
sp[zone->zone_rootpathlen - 2] = '\0'; |
|
1892 |
(void) strcat(sp, newpath); |
|
1893 |
||
1894 |
ref = refstr_alloc(sp); |
|
1895 |
kmem_free(sp, len); |
|
1896 |
out: |
|
1897 |
*refp = ref; |
|
1898 |
||
1899 |
if (have_list_lock) { |
|
1900 |
vfs_mnttab_modtimeupd(); |
|
1901 |
vfs_list_unlock(); |
|
1902 |
} |
|
1903 |
} |
|
1904 |
||
1905 |
/* |
|
1906 |
* Record a mounted resource name in a vfs structure. |
|
1907 |
* If vfsp is already mounted, caller must hold the vfs lock. |
|
1908 |
*/ |
|
1909 |
void |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1910 |
vfs_setresource(struct vfs *vfsp, const char *resource, uint32_t flag) |
0 | 1911 |
{ |
1912 |
if (resource == NULL || resource[0] == '\0') |
|
1913 |
resource = VFS_NORESOURCE; |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1914 |
vfs_setpath(vfsp, &vfsp->vfs_resource, resource, flag); |
0 | 1915 |
} |
1916 |
||
1917 |
/* |
|
1918 |
* Record a mount point name in a vfs structure. |
|
1919 |
* If vfsp is already mounted, caller must hold the vfs lock. |
|
1920 |
*/ |
|
1921 |
void |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1922 |
vfs_setmntpoint(struct vfs *vfsp, const char *mntpt, uint32_t flag) |
0 | 1923 |
{ |
1924 |
if (mntpt == NULL || mntpt[0] == '\0') |
|
1925 |
mntpt = VFS_NOMNTPT; |
|
12906
3ca11e9f39b7
6950914 remount can change mount point to "unspecified_mountpoint", causing panics
Robert Harris <Robert.Harris@Sun.COM>
parents:
12633
diff
changeset
|
1926 |
vfs_setpath(vfsp, &vfsp->vfs_mntpt, mntpt, flag); |
0 | 1927 |
} |
1928 |
||
1929 |
/* Returns the vfs_resource. Caller must call refstr_rele() when finished. */ |
|
1930 |
||
1931 |
refstr_t * |
|
1932 |
vfs_getresource(const struct vfs *vfsp) |
|
1933 |
{ |
|
1934 |
refstr_t *resource; |
|
1935 |
||
1936 |
vfs_list_read_lock(); |
|
1937 |
resource = vfsp->vfs_resource; |
|
1938 |
refstr_hold(resource); |
|
1939 |
vfs_list_unlock(); |
|
1940 |
||
1941 |
return (resource); |
|
1942 |
} |
|
1943 |
||
1944 |
/* Returns the vfs_mntpt. Caller must call refstr_rele() when finished. */ |
|
1945 |
||
1946 |
refstr_t * |
|
1947 |
vfs_getmntpoint(const struct vfs *vfsp) |
|
1948 |
{ |
|
1949 |
refstr_t *mntpt; |
|
1950 |
||
1951 |
vfs_list_read_lock(); |
|
1952 |
mntpt = vfsp->vfs_mntpt; |
|
1953 |
refstr_hold(mntpt); |
|
1954 |
vfs_list_unlock(); |
|
1955 |
||
1956 |
return (mntpt); |
|
1957 |
} |
|
1958 |
||
1959 |
/* |
|
1960 |
* Create an empty options table with enough empty slots to hold all |
|
1961 |
* The options in the options string passed as an argument. |
|
1962 |
* Potentially prepend another options table. |
|
1963 |
* |
|
1964 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
1965 |
* to protect mops. |
|
1966 |
*/ |
|
1967 |
static void |
|
1968 |
vfs_createopttbl_extend(mntopts_t *mops, const char *opts, |
|
1969 |
const mntopts_t *mtmpl) |
|
1970 |
{ |
|
1971 |
const char *s = opts; |
|
1972 |
uint_t count; |
|
1973 |
||
1974 |
if (opts == NULL || *opts == '\0') { |
|
1975 |
count = 0; |
|
1976 |
} else { |
|
1977 |
count = 1; |
|
1978 |
||
1979 |
/* |
|
1980 |
* Count number of options in the string |
|
1981 |
*/ |
|
1982 |
for (s = strchr(s, ','); s != NULL; s = strchr(s, ',')) { |
|
1983 |
count++; |
|
1984 |
s++; |
|
1985 |
} |
|
1986 |
} |
|
1987 |
vfs_copyopttbl_extend(mtmpl, mops, count); |
|
1988 |
} |
|
1989 |
||
1990 |
/* |
|
1991 |
* Create an empty options table with enough empty slots to hold all |
|
1992 |
* The options in the options string passed as an argument. |
|
1993 |
* |
|
1994 |
* This function is *not* for general use by filesystems. |
|
1995 |
* |
|
1996 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
1997 |
* to protect mops. |
|
1998 |
*/ |
|
1999 |
void |
|
2000 |
vfs_createopttbl(mntopts_t *mops, const char *opts) |
|
2001 |
{ |
|
2002 |
vfs_createopttbl_extend(mops, opts, NULL); |
|
2003 |
} |
|
2004 |
||
2005 |
||
2006 |
/* |
|
2007 |
* Swap two mount options tables |
|
2008 |
*/ |
|
2009 |
static void |
|
2010 |
vfs_swapopttbl_nolock(mntopts_t *optbl1, mntopts_t *optbl2) |
|
2011 |
{ |
|
2012 |
uint_t tmpcnt; |
|
2013 |
mntopt_t *tmplist; |
|
2014 |
||
2015 |
tmpcnt = optbl2->mo_count; |
|
2016 |
tmplist = optbl2->mo_list; |
|
2017 |
optbl2->mo_count = optbl1->mo_count; |
|
2018 |
optbl2->mo_list = optbl1->mo_list; |
|
2019 |
optbl1->mo_count = tmpcnt; |
|
2020 |
optbl1->mo_list = tmplist; |
|
2021 |
} |
|
2022 |
||
2023 |
static void |
|
2024 |
vfs_swapopttbl(mntopts_t *optbl1, mntopts_t *optbl2) |
|
2025 |
{ |
|
2026 |
vfs_list_lock(); |
|
2027 |
vfs_swapopttbl_nolock(optbl1, optbl2); |
|
2028 |
vfs_mnttab_modtimeupd(); |
|
2029 |
vfs_list_unlock(); |
|
2030 |
} |
|
2031 |
||
2032 |
static char ** |
|
2033 |
vfs_copycancelopt_extend(char **const moc, int extend) |
|
2034 |
{ |
|
2035 |
int i = 0; |
|
2036 |
int j; |
|
2037 |
char **result; |
|
2038 |
||
2039 |
if (moc != NULL) { |
|
2040 |
for (; moc[i] != NULL; i++) |
|
2041 |
/* count number of options to cancel */; |
|
2042 |
} |
|
2043 |
||
2044 |
if (i + extend == 0) |
|
2045 |
return (NULL); |
|
2046 |
||
2047 |
result = kmem_alloc((i + extend + 1) * sizeof (char *), KM_SLEEP); |
|
2048 |
||
2049 |
for (j = 0; j < i; j++) { |
|
2050 |
result[j] = kmem_alloc(strlen(moc[j]) + 1, KM_SLEEP); |
|
2051 |
(void) strcpy(result[j], moc[j]); |
|
2052 |
} |
|
2053 |
for (; j <= i + extend; j++) |
|
2054 |
result[j] = NULL; |
|
2055 |
||
2056 |
return (result); |
|
2057 |
} |
|
2058 |
||
2059 |
static void |
|
2060 |
vfs_copyopt(const mntopt_t *s, mntopt_t *d) |
|
2061 |
{ |
|
2062 |
char *sp, *dp; |
|
2063 |
||
2064 |
d->mo_flags = s->mo_flags; |
|
2065 |
d->mo_data = s->mo_data; |
|
2066 |
sp = s->mo_name; |
|
2067 |
if (sp != NULL) { |
|
2068 |
dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP); |
|
2069 |
(void) strcpy(dp, sp); |
|
2070 |
d->mo_name = dp; |
|
2071 |
} else { |
|
2072 |
d->mo_name = NULL; /* should never happen */ |
|
2073 |
} |
|
2074 |
||
2075 |
d->mo_cancel = vfs_copycancelopt_extend(s->mo_cancel, 0); |
|
2076 |
||
2077 |
sp = s->mo_arg; |
|
2078 |
if (sp != NULL) { |
|
2079 |
dp = kmem_alloc(strlen(sp) + 1, KM_SLEEP); |
|
2080 |
(void) strcpy(dp, sp); |
|
2081 |
d->mo_arg = dp; |
|
2082 |
} else { |
|
2083 |
d->mo_arg = NULL; |
|
2084 |
} |
|
2085 |
} |
|
2086 |
||
2087 |
/* |
|
2088 |
* Copy a mount options table, possibly allocating some spare |
|
2089 |
* slots at the end. It is permissible to copy_extend the NULL table. |
|
2090 |
*/ |
|
2091 |
static void |
|
2092 |
vfs_copyopttbl_extend(const mntopts_t *smo, mntopts_t *dmo, int extra) |
|
2093 |
{ |
|
2094 |
uint_t i, count; |
|
2095 |
mntopt_t *motbl; |
|
2096 |
||
2097 |
/* |
|
2098 |
* Clear out any existing stuff in the options table being initialized |
|
2099 |
*/ |
|
2100 |
vfs_freeopttbl(dmo); |
|
2101 |
count = (smo == NULL) ? 0 : smo->mo_count; |
|
2102 |
if ((count + extra) == 0) /* nothing to do */ |
|
2103 |
return; |
|
2104 |
dmo->mo_count = count + extra; |
|
2105 |
motbl = kmem_zalloc((count + extra) * sizeof (mntopt_t), KM_SLEEP); |
|
2106 |
dmo->mo_list = motbl; |
|
2107 |
for (i = 0; i < count; i++) { |
|
2108 |
vfs_copyopt(&smo->mo_list[i], &motbl[i]); |
|
2109 |
} |
|
2110 |
for (i = count; i < count + extra; i++) { |
|
2111 |
motbl[i].mo_flags = MO_EMPTY; |
|
2112 |
} |
|
2113 |
} |
|
2114 |
||
2115 |
/* |
|
2116 |
* Copy a mount options table. |
|
2117 |
* |
|
2118 |
* This function is *not* for general use by filesystems. |
|
2119 |
* |
|
2120 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2121 |
* to protect smo and dmo. |
|
2122 |
*/ |
|
2123 |
void |
|
2124 |
vfs_copyopttbl(const mntopts_t *smo, mntopts_t *dmo) |
|
2125 |
{ |
|
2126 |
vfs_copyopttbl_extend(smo, dmo, 0); |
|
2127 |
} |
|
2128 |
||
2129 |
static char ** |
|
2130 |
vfs_mergecancelopts(const mntopt_t *mop1, const mntopt_t *mop2) |
|
2131 |
{ |
|
2132 |
int c1 = 0; |
|
2133 |
int c2 = 0; |
|
2134 |
char **result; |
|
2135 |
char **sp1, **sp2, **dp; |
|
2136 |
||
2137 |
/* |
|
2138 |
* First we count both lists of cancel options. |
|
2139 |
* If either is NULL or has no elements, we return a copy of |
|
2140 |
* the other. |
|
2141 |
*/ |
|
2142 |
if (mop1->mo_cancel != NULL) { |
|
2143 |
for (; mop1->mo_cancel[c1] != NULL; c1++) |
|
2144 |
/* count cancel options in mop1 */; |
|
2145 |
} |
|
2146 |
||
2147 |
if (c1 == 0) |
|
2148 |
return (vfs_copycancelopt_extend(mop2->mo_cancel, 0)); |
|
2149 |
||
2150 |
if (mop2->mo_cancel != NULL) { |
|
2151 |
for (; mop2->mo_cancel[c2] != NULL; c2++) |
|
2152 |
/* count cancel options in mop2 */; |
|
2153 |
} |
|
2154 |
||
2155 |
result = vfs_copycancelopt_extend(mop1->mo_cancel, c2); |
|
2156 |
||
2157 |
if (c2 == 0) |
|
2158 |
return (result); |
|
2159 |
||
2160 |
/* |
|
2161 |
* When we get here, we've got two sets of cancel options; |
|
2162 |
* we need to merge the two sets. We know that the result |
|
2163 |
* array has "c1+c2+1" entries and in the end we might shrink |
|
2164 |
* it. |
|
2165 |
* Result now has a copy of the c1 entries from mop1; we'll |
|
2166 |
* now lookup all the entries of mop2 in mop1 and copy it if |
|
2167 |
* it is unique. |
|
2168 |
* This operation is O(n^2) but it's only called once per |
|
2169 |
* filesystem per duplicate option. This is a situation |
|
2170 |
* which doesn't arise with the filesystems in ON and |
|
2171 |
* n is generally 1. |
|
2172 |
*/ |
|
2173 |
||
2174 |
dp = &result[c1]; |
|
2175 |
for (sp2 = mop2->mo_cancel; *sp2 != NULL; sp2++) { |
|
2176 |
for (sp1 = mop1->mo_cancel; *sp1 != NULL; sp1++) { |
|
2177 |
if (strcmp(*sp1, *sp2) == 0) |
|
2178 |
break; |
|
2179 |
} |
|
2180 |
if (*sp1 == NULL) { |
|
2181 |
/* |
|
2182 |
* Option *sp2 not found in mop1, so copy it. |
|
2183 |
* The calls to vfs_copycancelopt_extend() |
|
2184 |
* guarantee that there's enough room. |
|
2185 |
*/ |
|
2186 |
*dp = kmem_alloc(strlen(*sp2) + 1, KM_SLEEP); |
|
2187 |
(void) strcpy(*dp++, *sp2); |
|
2188 |
} |
|
2189 |
} |
|
2190 |
if (dp != &result[c1+c2]) { |
|
2191 |
size_t bytes = (dp - result + 1) * sizeof (char *); |
|
2192 |
char **nres = kmem_alloc(bytes, KM_SLEEP); |
|
2193 |
||
2194 |
bcopy(result, nres, bytes); |
|
2195 |
kmem_free(result, (c1 + c2 + 1) * sizeof (char *)); |
|
2196 |
result = nres; |
|
2197 |
} |
|
2198 |
return (result); |
|
2199 |
} |
|
2200 |
||
2201 |
/* |
|
2202 |
* Merge two mount option tables (outer and inner) into one. This is very |
|
2203 |
* similar to "merging" global variables and automatic variables in C. |
|
2204 |
* |
|
2205 |
* This isn't (and doesn't have to be) fast. |
|
2206 |
* |
|
2207 |
* This function is *not* for general use by filesystems. |
|
2208 |
* |
|
2209 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2210 |
* to protect omo, imo & dmo. |
|
2211 |
*/ |
|
2212 |
void |
|
2213 |
vfs_mergeopttbl(const mntopts_t *omo, const mntopts_t *imo, mntopts_t *dmo) |
|
2214 |
{ |
|
2215 |
uint_t i, count; |
|
2216 |
mntopt_t *mop, *motbl; |
|
2217 |
uint_t freeidx; |
|
2218 |
||
2219 |
/* |
|
2220 |
* First determine how much space we need to allocate. |
|
2221 |
*/ |
|
2222 |
count = omo->mo_count; |
|
2223 |
for (i = 0; i < imo->mo_count; i++) { |
|
2224 |
if (imo->mo_list[i].mo_flags & MO_EMPTY) |
|
2225 |
continue; |
|
2226 |
if (vfs_hasopt(omo, imo->mo_list[i].mo_name) == NULL) |
|
2227 |
count++; |
|
2228 |
} |
|
2229 |
ASSERT(count >= omo->mo_count && |
|
2230 |
count <= omo->mo_count + imo->mo_count); |
|
2231 |
motbl = kmem_alloc(count * sizeof (mntopt_t), KM_SLEEP); |
|
2232 |
for (i = 0; i < omo->mo_count; i++) |
|
2233 |
vfs_copyopt(&omo->mo_list[i], &motbl[i]); |
|
2234 |
freeidx = omo->mo_count; |
|
2235 |
for (i = 0; i < imo->mo_count; i++) { |
|
2236 |
if (imo->mo_list[i].mo_flags & MO_EMPTY) |
|
2237 |
continue; |
|
2238 |
if ((mop = vfs_hasopt(omo, imo->mo_list[i].mo_name)) != NULL) { |
|
2239 |
char **newcanp; |
|
2240 |
uint_t index = mop - omo->mo_list; |
|
2241 |
||
2242 |
newcanp = vfs_mergecancelopts(mop, &motbl[index]); |
|
2243 |
||
2244 |
vfs_freeopt(&motbl[index]); |
|
2245 |
vfs_copyopt(&imo->mo_list[i], &motbl[index]); |
|
2246 |
||
2247 |
vfs_freecancelopt(motbl[index].mo_cancel); |
|
2248 |
motbl[index].mo_cancel = newcanp; |
|
2249 |
} else { |
|
2250 |
/* |
|
2251 |
* If it's a new option, just copy it over to the first |
|
2252 |
* free location. |
|
2253 |
*/ |
|
2254 |
vfs_copyopt(&imo->mo_list[i], &motbl[freeidx++]); |
|
2255 |
} |
|
2256 |
} |
|
2257 |
dmo->mo_count = count; |
|
2258 |
dmo->mo_list = motbl; |
|
2259 |
} |
|
2260 |
||
2261 |
/* |
|
2262 |
* Functions to set and clear mount options in a mount options table. |
|
2263 |
*/ |
|
2264 |
||
2265 |
/* |
|
2266 |
* Clear a mount option, if it exists. |
|
2267 |
* |
|
2268 |
* The update_mnttab arg indicates whether mops is part of a vfs that is on |
|
2269 |
* the vfs list. |
|
2270 |
*/ |
|
2271 |
static void |
|
2272 |
vfs_clearmntopt_nolock(mntopts_t *mops, const char *opt, int update_mnttab) |
|
2273 |
{ |
|
2274 |
struct mntopt *mop; |
|
2275 |
uint_t i, count; |
|
2276 |
||
2277 |
ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist)); |
|
2278 |
||
2279 |
count = mops->mo_count; |
|
2280 |
for (i = 0; i < count; i++) { |
|
2281 |
mop = &mops->mo_list[i]; |
|
2282 |
||
2283 |
if (mop->mo_flags & MO_EMPTY) |
|
2284 |
continue; |
|
2285 |
if (strcmp(opt, mop->mo_name)) |
|
2286 |
continue; |
|
2287 |
mop->mo_flags &= ~MO_SET; |
|
2288 |
if (mop->mo_arg != NULL) { |
|
2289 |
kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1); |
|
2290 |
} |
|
2291 |
mop->mo_arg = NULL; |
|
2292 |
if (update_mnttab) |
|
2293 |
vfs_mnttab_modtimeupd(); |
|
2294 |
break; |
|
2295 |
} |
|
2296 |
} |
|
2297 |
||
2298 |
void |
|
2299 |
vfs_clearmntopt(struct vfs *vfsp, const char *opt) |
|
2300 |
{ |
|
2301 |
int gotlock = 0; |
|
2302 |
||
2303 |
if (VFS_ON_LIST(vfsp)) { |
|
2304 |
gotlock = 1; |
|
2305 |
vfs_list_lock(); |
|
2306 |
} |
|
2307 |
vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, opt, gotlock); |
|
2308 |
if (gotlock) |
|
2309 |
vfs_list_unlock(); |
|
2310 |
} |
|
2311 |
||
2312 |
||
2313 |
/* |
|
2314 |
* Set a mount option on. If it's not found in the table, it's silently |
|
2315 |
* ignored. If the option has MO_IGNORE set, it is still set unless the |
|
2316 |
* VFS_NOFORCEOPT bit is set in the flags. Also, VFS_DISPLAY/VFS_NODISPLAY flag |
|
2317 |
* bits can be used to toggle the MO_NODISPLAY bit for the option. |
|
2318 |
* If the VFS_CREATEOPT flag bit is set then the first option slot with |
|
2319 |
* MO_EMPTY set is created as the option passed in. |
|
2320 |
* |
|
2321 |
* The update_mnttab arg indicates whether mops is part of a vfs that is on |
|
2322 |
* the vfs list. |
|
2323 |
*/ |
|
2324 |
static void |
|
2325 |
vfs_setmntopt_nolock(mntopts_t *mops, const char *opt, |
|
2326 |
const char *arg, int flags, int update_mnttab) |
|
2327 |
{ |
|
2328 |
mntopt_t *mop; |
|
2329 |
uint_t i, count; |
|
2330 |
char *sp; |
|
2331 |
||
2332 |
ASSERT(!update_mnttab || RW_WRITE_HELD(&vfslist)); |
|
2333 |
||
2334 |
if (flags & VFS_CREATEOPT) { |
|
2335 |
if (vfs_hasopt(mops, opt) != NULL) { |
|
2336 |
flags &= ~VFS_CREATEOPT; |
|
2337 |
} |
|
2338 |
} |
|
2339 |
count = mops->mo_count; |
|
2340 |
for (i = 0; i < count; i++) { |
|
2341 |
mop = &mops->mo_list[i]; |
|
2342 |
||
2343 |
if (mop->mo_flags & MO_EMPTY) { |
|
2344 |
if ((flags & VFS_CREATEOPT) == 0) |
|
2345 |
continue; |
|
2346 |
sp = kmem_alloc(strlen(opt) + 1, KM_SLEEP); |
|
2347 |
(void) strcpy(sp, opt); |
|
2348 |
mop->mo_name = sp; |
|
2349 |
if (arg != NULL) |
|
2350 |
mop->mo_flags = MO_HASVALUE; |
|
2351 |
else |
|
2352 |
mop->mo_flags = 0; |
|
2353 |
} else if (strcmp(opt, mop->mo_name)) { |
|
2354 |
continue; |
|
2355 |
} |
|
2356 |
if ((mop->mo_flags & MO_IGNORE) && (flags & VFS_NOFORCEOPT)) |
|
2357 |
break; |
|
2358 |
if (arg != NULL && (mop->mo_flags & MO_HASVALUE) != 0) { |
|
2359 |
sp = kmem_alloc(strlen(arg) + 1, KM_SLEEP); |
|
2360 |
(void) strcpy(sp, arg); |
|
2361 |
} else { |
|
2362 |
sp = NULL; |
|
2363 |
} |
|
2364 |
if (mop->mo_arg != NULL) |
|
2365 |
kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1); |
|
2366 |
mop->mo_arg = sp; |
|
2367 |
if (flags & VFS_DISPLAY) |
|
2368 |
mop->mo_flags &= ~MO_NODISPLAY; |
|
2369 |
if (flags & VFS_NODISPLAY) |
|
2370 |
mop->mo_flags |= MO_NODISPLAY; |
|
2371 |
mop->mo_flags |= MO_SET; |
|
2372 |
if (mop->mo_cancel != NULL) { |
|
2373 |
char **cp; |
|
2374 |
||
2375 |
for (cp = mop->mo_cancel; *cp != NULL; cp++) |
|
2376 |
vfs_clearmntopt_nolock(mops, *cp, 0); |
|
2377 |
} |
|
2378 |
if (update_mnttab) |
|
2379 |
vfs_mnttab_modtimeupd(); |
|
2380 |
break; |
|
2381 |
} |
|
2382 |
} |
|
2383 |
||
2384 |
void |
|
2385 |
vfs_setmntopt(struct vfs *vfsp, const char *opt, const char *arg, int flags) |
|
2386 |
{ |
|
2387 |
int gotlock = 0; |
|
2388 |
||
2389 |
if (VFS_ON_LIST(vfsp)) { |
|
2390 |
gotlock = 1; |
|
2391 |
vfs_list_lock(); |
|
2392 |
} |
|
2393 |
vfs_setmntopt_nolock(&vfsp->vfs_mntopts, opt, arg, flags, gotlock); |
|
2394 |
if (gotlock) |
|
2395 |
vfs_list_unlock(); |
|
2396 |
} |
|
2397 |
||
2398 |
||
2399 |
/* |
|
2400 |
* Add a "tag" option to a mounted file system's options list. |
|
2401 |
* |
|
2402 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2403 |
* to protect mops. |
|
2404 |
*/ |
|
2405 |
static mntopt_t * |
|
2406 |
vfs_addtag(mntopts_t *mops, const char *tag) |
|
2407 |
{ |
|
2408 |
uint_t count; |
|
2409 |
mntopt_t *mop, *motbl; |
|
2410 |
||
2411 |
count = mops->mo_count + 1; |
|
2412 |
motbl = kmem_zalloc(count * sizeof (mntopt_t), KM_SLEEP); |
|
2413 |
if (mops->mo_count) { |
|
2414 |
size_t len = (count - 1) * sizeof (mntopt_t); |
|
2415 |
||
2416 |
bcopy(mops->mo_list, motbl, len); |
|
2417 |
kmem_free(mops->mo_list, len); |
|
2418 |
} |
|
2419 |
mops->mo_count = count; |
|
2420 |
mops->mo_list = motbl; |
|
2421 |
mop = &motbl[count - 1]; |
|
2422 |
mop->mo_flags = MO_TAG; |
|
2423 |
mop->mo_name = kmem_alloc(strlen(tag) + 1, KM_SLEEP); |
|
2424 |
(void) strcpy(mop->mo_name, tag); |
|
2425 |
return (mop); |
|
2426 |
} |
|
2427 |
||
2428 |
/* |
|
2429 |
* Allow users to set arbitrary "tags" in a vfs's mount options. |
|
2430 |
* Broader use within the kernel is discouraged. |
|
2431 |
*/ |
|
2432 |
int |
|
2433 |
vfs_settag(uint_t major, uint_t minor, const char *mntpt, const char *tag, |
|
2434 |
cred_t *cr) |
|
2435 |
{ |
|
2436 |
vfs_t *vfsp; |
|
2437 |
mntopts_t *mops; |
|
2438 |
mntopt_t *mop; |
|
2439 |
int found = 0; |
|
2440 |
dev_t dev = makedevice(major, minor); |
|
2441 |
int err = 0; |
|
2442 |
char *buf = kmem_alloc(MAX_MNTOPT_STR, KM_SLEEP); |
|
2443 |
||
2444 |
/* |
|
2445 |
* Find the desired mounted file system |
|
2446 |
*/ |
|
2447 |
vfs_list_lock(); |
|
2448 |
vfsp = rootvfs; |
|
2449 |
do { |
|
2450 |
if (vfsp->vfs_dev == dev && |
|
2451 |
strcmp(mntpt, refstr_value(vfsp->vfs_mntpt)) == 0) { |
|
2452 |
found = 1; |
|
2453 |
break; |
|
2454 |
} |
|
2455 |
vfsp = vfsp->vfs_next; |
|
2456 |
} while (vfsp != rootvfs); |
|
2457 |
||
2458 |
if (!found) { |
|
2459 |
err = EINVAL; |
|
2460 |
goto out; |
|
2461 |
} |
|
2462 |
err = secpolicy_fs_config(cr, vfsp); |
|
2463 |
if (err != 0) |
|
2464 |
goto out; |
|
2465 |
||
2466 |
mops = &vfsp->vfs_mntopts; |
|
2467 |
/* |
|
2468 |
* Add tag if it doesn't already exist |
|
2469 |
*/ |
|
2470 |
if ((mop = vfs_hasopt(mops, tag)) == NULL) { |
|
2471 |
int len; |
|
2472 |
||
2473 |
(void) vfs_buildoptionstr(mops, buf, MAX_MNTOPT_STR); |
|
2474 |
len = strlen(buf); |
|
2475 |
if (len + strlen(tag) + 2 > MAX_MNTOPT_STR) { |
|
2476 |
err = ENAMETOOLONG; |
|
2477 |
goto out; |
|
2478 |
} |
|
2479 |
mop = vfs_addtag(mops, tag); |
|
2480 |
} |
|
2481 |
if ((mop->mo_flags & MO_TAG) == 0) { |
|
2482 |
err = EINVAL; |
|
2483 |
goto out; |
|
2484 |
} |
|
2485 |
vfs_setmntopt_nolock(mops, tag, NULL, 0, 1); |
|
2486 |
out: |
|
2487 |
vfs_list_unlock(); |
|
2488 |
kmem_free(buf, MAX_MNTOPT_STR); |
|
2489 |
return (err); |
|
2490 |
} |
|
2491 |
||
2492 |
/* |
|
2493 |
* Allow users to remove arbitrary "tags" in a vfs's mount options. |
|
2494 |
* Broader use within the kernel is discouraged. |
|
2495 |
*/ |
|
2496 |
int |
|
2497 |
vfs_clrtag(uint_t major, uint_t minor, const char *mntpt, const char *tag, |
|
2498 |
cred_t *cr) |
|
2499 |
{ |
|
2500 |
vfs_t *vfsp; |
|
2501 |
mntopt_t *mop; |
|
2502 |
int found = 0; |
|
2503 |
dev_t dev = makedevice(major, minor); |
|
2504 |
int err = 0; |
|
2505 |
||
2506 |
/* |
|
2507 |
* Find the desired mounted file system |
|
2508 |
*/ |
|
2509 |
vfs_list_lock(); |
|
2510 |
vfsp = rootvfs; |
|
2511 |
do { |
|
2512 |
if (vfsp->vfs_dev == dev && |
|
2513 |
strcmp(mntpt, refstr_value(vfsp->vfs_mntpt)) == 0) { |
|
2514 |
found = 1; |
|
2515 |
break; |
|
2516 |
} |
|
2517 |
vfsp = vfsp->vfs_next; |
|
2518 |
} while (vfsp != rootvfs); |
|
2519 |
||
2520 |
if (!found) { |
|
2521 |
err = EINVAL; |
|
2522 |
goto out; |
|
2523 |
} |
|
2524 |
err = secpolicy_fs_config(cr, vfsp); |
|
2525 |
if (err != 0) |
|
2526 |
goto out; |
|
2527 |
||
2528 |
if ((mop = vfs_hasopt(&vfsp->vfs_mntopts, tag)) == NULL) { |
|
2529 |
err = EINVAL; |
|
2530 |
goto out; |
|
2531 |
} |
|
2532 |
if ((mop->mo_flags & MO_TAG) == 0) { |
|
2533 |
err = EINVAL; |
|
2534 |
goto out; |
|
2535 |
} |
|
2536 |
vfs_clearmntopt_nolock(&vfsp->vfs_mntopts, tag, 1); |
|
2537 |
out: |
|
2538 |
vfs_list_unlock(); |
|
2539 |
return (err); |
|
2540 |
} |
|
2541 |
||
2542 |
/* |
|
2543 |
* Function to parse an option string and fill in a mount options table. |
|
2544 |
* Unknown options are silently ignored. The input option string is modified |
|
2545 |
* by replacing separators with nulls. If the create flag is set, options |
|
2546 |
* not found in the table are just added on the fly. The table must have |
|
2547 |
* an option slot marked MO_EMPTY to add an option on the fly. |
|
2548 |
* |
|
2549 |
* This function is *not* for general use by filesystems. |
|
2550 |
* |
|
2551 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2552 |
* to protect mops.. |
|
2553 |
*/ |
|
2554 |
void |
|
2555 |
vfs_parsemntopts(mntopts_t *mops, char *osp, int create) |
|
2556 |
{ |
|
2557 |
char *s = osp, *p, *nextop, *valp, *cp, *ep; |
|
2558 |
int setflg = VFS_NOFORCEOPT; |
|
2559 |
||
2560 |
if (osp == NULL) |
|
2561 |
return; |
|
2562 |
while (*s != '\0') { |
|
2563 |
p = strchr(s, ','); /* find next option */ |
|
2564 |
if (p == NULL) { |
|
2565 |
cp = NULL; |
|
2566 |
p = s + strlen(s); |
|
2567 |
} else { |
|
2568 |
cp = p; /* save location of comma */ |
|
2569 |
*p++ = '\0'; /* mark end and point to next option */ |
|
2570 |
} |
|
2571 |
nextop = p; |
|
2572 |
p = strchr(s, '='); /* look for value */ |
|
2573 |
if (p == NULL) { |
|
2574 |
valp = NULL; /* no value supplied */ |
|
2575 |
} else { |
|
2576 |
ep = p; /* save location of equals */ |
|
2577 |
*p++ = '\0'; /* end option and point to value */ |
|
2578 |
valp = p; |
|
2579 |
} |
|
2580 |
/* |
|
2581 |
* set option into options table |
|
2582 |
*/ |
|
2583 |
if (create) |
|
2584 |
setflg |= VFS_CREATEOPT; |
|
2585 |
vfs_setmntopt_nolock(mops, s, valp, setflg, 0); |
|
2586 |
if (cp != NULL) |
|
2587 |
*cp = ','; /* restore the comma */ |
|
2588 |
if (valp != NULL) |
|
2589 |
*ep = '='; /* restore the equals */ |
|
2590 |
s = nextop; |
|
2591 |
} |
|
2592 |
} |
|
2593 |
||
2594 |
/* |
|
2595 |
* Function to inquire if an option exists in a mount options table. |
|
2596 |
* Returns a pointer to the option if it exists, else NULL. |
|
2597 |
* |
|
2598 |
* This function is *not* for general use by filesystems. |
|
2599 |
* |
|
2600 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2601 |
* to protect mops. |
|
2602 |
*/ |
|
2603 |
struct mntopt * |
|
2604 |
vfs_hasopt(const mntopts_t *mops, const char *opt) |
|
2605 |
{ |
|
2606 |
struct mntopt *mop; |
|
2607 |
uint_t i, count; |
|
2608 |
||
2609 |
count = mops->mo_count; |
|
2610 |
for (i = 0; i < count; i++) { |
|
2611 |
mop = &mops->mo_list[i]; |
|
2612 |
||
2613 |
if (mop->mo_flags & MO_EMPTY) |
|
2614 |
continue; |
|
2615 |
if (strcmp(opt, mop->mo_name) == 0) |
|
2616 |
return (mop); |
|
2617 |
} |
|
2618 |
return (NULL); |
|
2619 |
} |
|
2620 |
||
2621 |
/* |
|
2622 |
* Function to inquire if an option is set in a mount options table. |
|
2623 |
* Returns non-zero if set and fills in the arg pointer with a pointer to |
|
2624 |
* the argument string or NULL if there is no argument string. |
|
2625 |
*/ |
|
2626 |
static int |
|
2627 |
vfs_optionisset_nolock(const mntopts_t *mops, const char *opt, char **argp) |
|
2628 |
{ |
|
2629 |
struct mntopt *mop; |
|
2630 |
uint_t i, count; |
|
2631 |
||
2632 |
count = mops->mo_count; |
|
2633 |
for (i = 0; i < count; i++) { |
|
2634 |
mop = &mops->mo_list[i]; |
|
2635 |
||
2636 |
if (mop->mo_flags & MO_EMPTY) |
|
2637 |
continue; |
|
2638 |
if (strcmp(opt, mop->mo_name)) |
|
2639 |
continue; |
|
2640 |
if ((mop->mo_flags & MO_SET) == 0) |
|
2641 |
return (0); |
|
2642 |
if (argp != NULL && (mop->mo_flags & MO_HASVALUE) != 0) |
|
2643 |
*argp = mop->mo_arg; |
|
2644 |
return (1); |
|
2645 |
} |
|
2646 |
return (0); |
|
2647 |
} |
|
2648 |
||
2649 |
||
2650 |
int |
|
2651 |
vfs_optionisset(const struct vfs *vfsp, const char *opt, char **argp) |
|
2652 |
{ |
|
2653 |
int ret; |
|
2654 |
||
2655 |
vfs_list_read_lock(); |
|
2656 |
ret = vfs_optionisset_nolock(&vfsp->vfs_mntopts, opt, argp); |
|
2657 |
vfs_list_unlock(); |
|
2658 |
return (ret); |
|
2659 |
} |
|
2660 |
||
2661 |
||
2662 |
/* |
|
2663 |
* Construct a comma separated string of the options set in the given |
|
2664 |
* mount table, return the string in the given buffer. Return non-zero if |
|
2665 |
* the buffer would overflow. |
|
2666 |
* |
|
2667 |
* This function is *not* for general use by filesystems. |
|
2668 |
* |
|
2669 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2670 |
* to protect mp. |
|
2671 |
*/ |
|
2672 |
int |
|
2673 |
vfs_buildoptionstr(const mntopts_t *mp, char *buf, int len) |
|
2674 |
{ |
|
2675 |
char *cp; |
|
2676 |
uint_t i; |
|
2677 |
||
2678 |
buf[0] = '\0'; |
|
2679 |
cp = buf; |
|
2680 |
for (i = 0; i < mp->mo_count; i++) { |
|
2681 |
struct mntopt *mop; |
|
2682 |
||
2683 |
mop = &mp->mo_list[i]; |
|
2684 |
if (mop->mo_flags & MO_SET) { |
|
2685 |
int optlen, comma = 0; |
|
2686 |
||
2687 |
if (buf[0] != '\0') |
|
2688 |
comma = 1; |
|
2689 |
optlen = strlen(mop->mo_name); |
|
2690 |
if (strlen(buf) + comma + optlen + 1 > len) |
|
2691 |
goto err; |
|
2692 |
if (comma) |
|
2693 |
*cp++ = ','; |
|
2694 |
(void) strcpy(cp, mop->mo_name); |
|
2695 |
cp += optlen; |
|
2696 |
/* |
|
2697 |
* Append option value if there is one |
|
2698 |
*/ |
|
2699 |
if (mop->mo_arg != NULL) { |
|
2700 |
int arglen; |
|
2701 |
||
2702 |
arglen = strlen(mop->mo_arg); |
|
2703 |
if (strlen(buf) + arglen + 2 > len) |
|
2704 |
goto err; |
|
2705 |
*cp++ = '='; |
|
2706 |
(void) strcpy(cp, mop->mo_arg); |
|
2707 |
cp += arglen; |
|
2708 |
} |
|
2709 |
} |
|
2710 |
} |
|
2711 |
return (0); |
|
2712 |
err: |
|
2713 |
return (EOVERFLOW); |
|
2714 |
} |
|
2715 |
||
2716 |
static void |
|
2717 |
vfs_freecancelopt(char **moc) |
|
2718 |
{ |
|
2719 |
if (moc != NULL) { |
|
2720 |
int ccnt = 0; |
|
2721 |
char **cp; |
|
2722 |
||
2723 |
for (cp = moc; *cp != NULL; cp++) { |
|
2724 |
kmem_free(*cp, strlen(*cp) + 1); |
|
2725 |
ccnt++; |
|
2726 |
} |
|
2727 |
kmem_free(moc, (ccnt + 1) * sizeof (char *)); |
|
2728 |
} |
|
2729 |
} |
|
2730 |
||
2731 |
static void |
|
2732 |
vfs_freeopt(mntopt_t *mop) |
|
2733 |
{ |
|
2734 |
if (mop->mo_name != NULL) |
|
2735 |
kmem_free(mop->mo_name, strlen(mop->mo_name) + 1); |
|
2736 |
||
2737 |
vfs_freecancelopt(mop->mo_cancel); |
|
2738 |
||
2739 |
if (mop->mo_arg != NULL) |
|
2740 |
kmem_free(mop->mo_arg, strlen(mop->mo_arg) + 1); |
|
2741 |
} |
|
2742 |
||
2743 |
/* |
|
2744 |
* Free a mount options table |
|
2745 |
* |
|
2746 |
* This function is *not* for general use by filesystems. |
|
2747 |
* |
|
2748 |
* Note: caller is responsible for locking the vfs list, if needed, |
|
2749 |
* to protect mp. |
|
2750 |
*/ |
|
2751 |
void |
|
2752 |
vfs_freeopttbl(mntopts_t *mp) |
|
2753 |
{ |
|
2754 |
uint_t i, count; |
|
2755 |
||
2756 |
count = mp->mo_count; |
|
2757 |
for (i = 0; i < count; i++) { |
|
2758 |
vfs_freeopt(&mp->mo_list[i]); |
|
2759 |
} |
|
2760 |
if (count) { |
|
2761 |
kmem_free(mp->mo_list, sizeof (mntopt_t) * count); |
|
2762 |
mp->mo_count = 0; |
|
2763 |
mp->mo_list = NULL; |
|
2764 |
} |
|
2765 |
} |
|
2766 |
||
4863 | 2767 |
|
2768 |
/* ARGSUSED */ |
|
2769 |
static int |
|
2770 |
vfs_mntdummyread(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, |
|
2771 |
caller_context_t *ct) |
|
2772 |
{ |
|
2773 |
return (0); |
|
2774 |
} |
|
2775 |
||
2776 |
/* ARGSUSED */ |
|
2777 |
static int |
|
2778 |
vfs_mntdummywrite(vnode_t *vp, uio_t *uio, int ioflag, cred_t *cred, |
|
2779 |
caller_context_t *ct) |
|
2780 |
{ |
|
2781 |
return (0); |
|
2782 |
} |
|
2783 |
||
2784 |
/* |
|
2785 |
* The dummy vnode is currently used only by file events notification |
|
2786 |
* module which is just interested in the timestamps. |
|
2787 |
*/ |
|
2788 |
/* ARGSUSED */ |
|
2789 |
static int |
|
5331 | 2790 |
vfs_mntdummygetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr, |
2791 |
caller_context_t *ct) |
|
4863 | 2792 |
{ |
2793 |
bzero(vap, sizeof (vattr_t)); |
|
2794 |
vap->va_type = VREG; |
|
2795 |
vap->va_nlink = 1; |
|
2796 |
vap->va_ctime = vfs_mnttab_ctime; |
|
2797 |
/* |
|
2798 |
* it is ok to just copy mtime as the time will be monotonically |
|
2799 |
* increasing. |
|
2800 |
*/ |
|
2801 |
vap->va_mtime = vfs_mnttab_mtime; |
|
2802 |
vap->va_atime = vap->va_mtime; |
|
2803 |
return (0); |
|
2804 |
} |
|
2805 |
||
2806 |
static void |
|
2807 |
vfs_mnttabvp_setup(void) |
|
2808 |
{ |
|
2809 |
vnode_t *tvp; |
|
2810 |
vnodeops_t *vfs_mntdummyvnops; |
|
2811 |
const fs_operation_def_t mnt_dummyvnodeops_template[] = { |
|
2812 |
VOPNAME_READ, { .vop_read = vfs_mntdummyread }, |
|
2813 |
VOPNAME_WRITE, { .vop_write = vfs_mntdummywrite }, |
|
2814 |
VOPNAME_GETATTR, { .vop_getattr = vfs_mntdummygetattr }, |
|
2815 |
VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support }, |
|
2816 |
NULL, NULL |
|
2817 |
}; |
|
2818 |
||
2819 |
if (vn_make_ops("mnttab", mnt_dummyvnodeops_template, |
|
2820 |
&vfs_mntdummyvnops) != 0) { |
|
2821 |
cmn_err(CE_WARN, "vfs_mnttabvp_setup: vn_make_ops failed"); |
|
2822 |
/* Shouldn't happen, but not bad enough to panic */ |
|
2823 |
return; |
|
2824 |
} |
|
2825 |
||
2826 |
/* |
|
2827 |
* A global dummy vnode is allocated to represent mntfs files. |
|
2828 |
* The mntfs file (/etc/mnttab) can be monitored for file events |
|
2829 |
* and receive an event when mnttab changes. Dummy VOP calls |
|
2830 |
* will be made on this vnode. The file events notification module |
|
2831 |
* intercepts this vnode and delivers relevant events. |
|
2832 |
*/ |
|
2833 |
tvp = vn_alloc(KM_SLEEP); |
|
2834 |
tvp->v_flag = VNOMOUNT|VNOMAP|VNOSWAP|VNOCACHE; |
|
2835 |
vn_setops(tvp, vfs_mntdummyvnops); |
|
2836 |
tvp->v_type = VREG; |
|
2837 |
/* |
|
2838 |
* The mnt dummy ops do not reference v_data. |
|
2839 |
* No other module intercepting this vnode should either. |
|
2840 |
* Just set it to point to itself. |
|
2841 |
*/ |
|
2842 |
tvp->v_data = (caddr_t)tvp; |
|
2843 |
tvp->v_vfsp = rootvfs; |
|
2844 |
vfs_mntdummyvp = tvp; |
|
2845 |
} |
|
2846 |
||
2847 |
/* |
|
2848 |
* performs fake read/write ops |
|
2849 |
*/ |
|
2850 |
static void |
|
2851 |
vfs_mnttab_rwop(int rw) |
|
2852 |
{ |
|
2853 |
struct uio uio; |
|
2854 |
struct iovec iov; |
|
2855 |
char buf[1]; |
|
2856 |
||
2857 |
if (vfs_mntdummyvp == NULL) |
|
2858 |
return; |
|
2859 |
||
2860 |
bzero(&uio, sizeof (uio)); |
|
2861 |
bzero(&iov, sizeof (iov)); |
|
2862 |
iov.iov_base = buf; |
|
2863 |
iov.iov_len = 0; |
|
2864 |
uio.uio_iov = &iov; |
|
2865 |
uio.uio_iovcnt = 1; |
|
2866 |
uio.uio_loffset = 0; |
|
2867 |
uio.uio_segflg = UIO_SYSSPACE; |
|
2868 |
uio.uio_resid = 0; |
|
2869 |
if (rw) { |
|
2870 |
(void) VOP_WRITE(vfs_mntdummyvp, &uio, 0, kcred, NULL); |
|
2871 |
} else { |
|
2872 |
(void) VOP_READ(vfs_mntdummyvp, &uio, 0, kcred, NULL); |
|
2873 |
} |
|
2874 |
} |
|
2875 |
||
2876 |
/* |
|
2877 |
* Generate a write operation. |
|
2878 |
*/ |
|
2879 |
void |
|
2880 |
vfs_mnttab_writeop(void) |
|
2881 |
{ |
|
2882 |
vfs_mnttab_rwop(1); |
|
2883 |
} |
|
2884 |
||
2885 |
/* |
|
2886 |
* Generate a read operation. |
|
2887 |
*/ |
|
2888 |
void |
|
2889 |
vfs_mnttab_readop(void) |
|
2890 |
{ |
|
2891 |
vfs_mnttab_rwop(0); |
|
2892 |
} |
|
2893 |
||
0 | 2894 |
/* |
2895 |
* Free any mnttab information recorded in the vfs struct. |
|
2896 |
* The vfs must not be on the vfs list. |
|
2897 |
*/ |
|
2898 |
static void |
|
2899 |
vfs_freemnttab(struct vfs *vfsp) |
|
2900 |
{ |
|
2901 |
ASSERT(!VFS_ON_LIST(vfsp)); |
|
2902 |
||
2903 |
/* |
|
2904 |
* Free device and mount point information |
|
2905 |
*/ |
|
2906 |
if (vfsp->vfs_mntpt != NULL) { |
|
2907 |
refstr_rele(vfsp->vfs_mntpt); |
|
2908 |
vfsp->vfs_mntpt = NULL; |
|
2909 |
} |
|
2910 |
if (vfsp->vfs_resource != NULL) { |
|
2911 |
refstr_rele(vfsp->vfs_resource); |
|
2912 |
vfsp->vfs_resource = NULL; |
|
2913 |
} |
|
2914 |
/* |
|
2915 |
* Now free mount options information |
|
2916 |
*/ |
|
2917 |
vfs_freeopttbl(&vfsp->vfs_mntopts); |
|
2918 |
} |
|
2919 |
||
2920 |
/* |
|
2921 |
* Return the last mnttab modification time |
|
2922 |
*/ |
|
2923 |
void |
|
2924 |
vfs_mnttab_modtime(timespec_t *ts) |
|
2925 |
{ |
|
2926 |
ASSERT(RW_LOCK_HELD(&vfslist)); |
|
2927 |
*ts = vfs_mnttab_mtime; |
|
2928 |
} |
|
2929 |
||
2930 |
/* |
|
2931 |
* See if mnttab is changed |
|
2932 |
*/ |
|
2933 |
void |
|
2934 |
vfs_mnttab_poll(timespec_t *old, struct pollhead **phpp) |
|
2935 |
{ |
|
2936 |
int changed; |
|
2937 |
||
2938 |
*phpp = (struct pollhead *)NULL; |
|
2939 |
||
2940 |
/* |
|
2941 |
* Note: don't grab vfs list lock before accessing vfs_mnttab_mtime. |
|
2942 |
* Can lead to deadlock against vfs_mnttab_modtimeupd(). It is safe |
|
2943 |
* to not grab the vfs list lock because tv_sec is monotonically |
|
2944 |
* increasing. |
|
2945 |
*/ |
|
2946 |
||
2947 |
changed = (old->tv_nsec != vfs_mnttab_mtime.tv_nsec) || |
|
2948 |
(old->tv_sec != vfs_mnttab_mtime.tv_sec); |
|
2949 |
if (!changed) { |
|
2950 |
*phpp = &vfs_pollhd; |
|
2951 |
} |
|
2952 |
} |
|
2953 |
||
10910
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2954 |
/* Provide a unique and monotonically-increasing timestamp. */ |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2955 |
void |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2956 |
vfs_mono_time(timespec_t *ts) |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2957 |
{ |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2958 |
static volatile hrtime_t hrt; /* The saved time. */ |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2959 |
hrtime_t newhrt, oldhrt; /* For effecting the CAS. */ |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2960 |
timespec_t newts; |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2961 |
|
11005
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2962 |
/* |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2963 |
* Try gethrestime() first, but be prepared to fabricate a sensible |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2964 |
* answer at the first sign of any trouble. |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2965 |
*/ |
10910
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2966 |
gethrestime(&newts); |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2967 |
newhrt = ts2hrt(&newts); |
11005
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2968 |
for (;;) { |
10910
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2969 |
oldhrt = hrt; |
11005
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2970 |
if (newhrt <= hrt) |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2971 |
newhrt = hrt + 1; |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2972 |
if (cas64((uint64_t *)&hrt, oldhrt, newhrt) == oldhrt) |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2973 |
break; |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2974 |
} |
10910
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2975 |
hrt2ts(newhrt, ts); |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2976 |
} |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
2977 |
|
0 | 2978 |
/* |
2979 |
* Update the mnttab modification time and wake up any waiters for |
|
2980 |
* mnttab changes |
|
2981 |
*/ |
|
2982 |
void |
|
2983 |
vfs_mnttab_modtimeupd() |
|
2984 |
{ |
|
11005
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2985 |
hrtime_t oldhrt, newhrt; |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2986 |
|
0 | 2987 |
ASSERT(RW_WRITE_HELD(&vfslist)); |
11005
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2988 |
oldhrt = ts2hrt(&vfs_mnttab_mtime); |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2989 |
gethrestime(&vfs_mnttab_mtime); |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2990 |
newhrt = ts2hrt(&vfs_mnttab_mtime); |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2991 |
if (oldhrt == (hrtime_t)0) |
0 | 2992 |
vfs_mnttab_ctime = vfs_mnttab_mtime; |
11005
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2993 |
/* |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2994 |
* Attempt to provide unique mtime (like uniqtime but not). |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2995 |
*/ |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2996 |
if (newhrt == oldhrt) { |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2997 |
newhrt++; |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2998 |
hrt2ts(newhrt, &vfs_mnttab_mtime); |
fe42ca39a510
6898786 vfs_mono_time() can produce time stamps from the past
Robert Harris <Robert.Harris@Sun.COM>
parents:
10922
diff
changeset
|
2999 |
} |
0 | 3000 |
pollwakeup(&vfs_pollhd, (short)POLLRDBAND); |
4863 | 3001 |
vfs_mnttab_writeop(); |
0 | 3002 |
} |
3003 |
||
3004 |
int |
|
3005 |
dounmount(struct vfs *vfsp, int flag, cred_t *cr) |
|
3006 |
{ |
|
3007 |
vnode_t *coveredvp; |
|
3008 |
int error; |
|
1488 | 3009 |
extern void teardown_vopstats(vfs_t *); |
0 | 3010 |
|
3011 |
/* |
|
3012 |
* Get covered vnode. This will be NULL if the vfs is not linked |
|
3013 |
* into the file system name space (i.e., domount() with MNT_NOSPICE). |
|
3014 |
*/ |
|
3015 |
coveredvp = vfsp->vfs_vnodecovered; |
|
3016 |
ASSERT(coveredvp == NULL || vn_vfswlock_held(coveredvp)); |
|
3017 |
||
3018 |
/* |
|
3019 |
* Purge all dnlc entries for this vfs. |
|
3020 |
*/ |
|
3021 |
(void) dnlc_purge_vfsp(vfsp, 0); |
|
3022 |
||
3023 |
/* For forcible umount, skip VFS_SYNC() since it may hang */ |
|
3024 |
if ((flag & MS_FORCE) == 0) |
|
3025 |
(void) VFS_SYNC(vfsp, 0, cr); |
|
3026 |
||
3027 |
/* |
|
3028 |
* Lock the vfs to maintain fs status quo during unmount. This |
|
3029 |
* has to be done after the sync because ufs_update tries to acquire |
|
3030 |
* the vfs_reflock. |
|
3031 |
*/ |
|
3032 |
vfs_lock_wait(vfsp); |
|
3033 |
||
3034 |
if (error = VFS_UNMOUNT(vfsp, flag, cr)) { |
|
3035 |
vfs_unlock(vfsp); |
|
3036 |
if (coveredvp != NULL) |
|
3037 |
vn_vfsunlock(coveredvp); |
|
3038 |
} else if (coveredvp != NULL) { |
|
1488 | 3039 |
teardown_vopstats(vfsp); |
0 | 3040 |
/* |
3041 |
* vfs_remove() will do a VN_RELE(vfsp->vfs_vnodecovered) |
|
3042 |
* when it frees vfsp so we do a VN_HOLD() so we can |
|
3043 |
* continue to use coveredvp afterwards. |
|
3044 |
*/ |
|
3045 |
VN_HOLD(coveredvp); |
|
3046 |
vfs_remove(vfsp); |
|
3047 |
vn_vfsunlock(coveredvp); |
|
3048 |
VN_RELE(coveredvp); |
|
3049 |
} else { |
|
1488 | 3050 |
teardown_vopstats(vfsp); |
0 | 3051 |
/* |
3052 |
* Release the reference to vfs that is not linked |
|
3053 |
* into the name space. |
|
3054 |
*/ |
|
3055 |
vfs_unlock(vfsp); |
|
3056 |
VFS_RELE(vfsp); |
|
3057 |
} |
|
3058 |
return (error); |
|
3059 |
} |
|
3060 |
||
3061 |
||
3062 |
/* |
|
3063 |
* Vfs_unmountall() is called by uadmin() to unmount all |
|
3064 |
* mounted file systems (except the root file system) during shutdown. |
|
3065 |
* It follows the existing locking protocol when traversing the vfs list |
|
3066 |
* to sync and unmount vfses. Even though there should be no |
|
3067 |
* other thread running while the system is shutting down, it is prudent |
|
3068 |
* to still follow the locking protocol. |
|
3069 |
*/ |
|
3070 |
void |
|
3071 |
vfs_unmountall(void) |
|
3072 |
{ |
|
3073 |
struct vfs *vfsp; |
|
3074 |
struct vfs *prev_vfsp = NULL; |
|
3075 |
int error; |
|
3076 |
||
3077 |
/* |
|
3078 |
* Toss all dnlc entries now so that the per-vfs sync |
|
3079 |
* and unmount operations don't have to slog through |
|
3080 |
* a bunch of uninteresting vnodes over and over again. |
|
3081 |
*/ |
|
3082 |
dnlc_purge(); |
|
3083 |
||
3084 |
vfs_list_lock(); |
|
3085 |
for (vfsp = rootvfs->vfs_prev; vfsp != rootvfs; vfsp = prev_vfsp) { |
|
3086 |
prev_vfsp = vfsp->vfs_prev; |
|
3087 |
||
3088 |
if (vfs_lock(vfsp) != 0) |
|
3089 |
continue; |
|
3090 |
error = vn_vfswlock(vfsp->vfs_vnodecovered); |
|
3091 |
vfs_unlock(vfsp); |
|
3092 |
if (error) |
|
3093 |
continue; |
|
3094 |
||
3095 |
vfs_list_unlock(); |
|
3096 |
||
3097 |
(void) VFS_SYNC(vfsp, SYNC_CLOSE, CRED()); |
|
3098 |
(void) dounmount(vfsp, 0, CRED()); |
|
3099 |
||
3100 |
/* |
|
3101 |
* Since we dropped the vfslist lock above we must |
|
3102 |
* verify that next_vfsp still exists, else start over. |
|
3103 |
*/ |
|
3104 |
vfs_list_lock(); |
|
3105 |
for (vfsp = rootvfs->vfs_prev; |
|
3912 | 3106 |
vfsp != rootvfs; vfsp = vfsp->vfs_prev) |
0 | 3107 |
if (vfsp == prev_vfsp) |
3108 |
break; |
|
3109 |
if (vfsp == rootvfs && prev_vfsp != rootvfs) |
|
3110 |
prev_vfsp = rootvfs->vfs_prev; |
|
3111 |
} |
|
3112 |
vfs_list_unlock(); |
|
3113 |
} |
|
3114 |
||
3115 |
/* |
|
3116 |
* Called to add an entry to the end of the vfs mount in progress list |
|
3117 |
*/ |
|
3118 |
void |
|
3119 |
vfs_addmip(dev_t dev, struct vfs *vfsp) |
|
3120 |
{ |
|
3121 |
struct ipmnt *mipp; |
|
3122 |
||
3123 |
mipp = (struct ipmnt *)kmem_alloc(sizeof (struct ipmnt), KM_SLEEP); |
|
3124 |
mipp->mip_next = NULL; |
|
3125 |
mipp->mip_dev = dev; |
|
3126 |
mipp->mip_vfsp = vfsp; |
|
3127 |
mutex_enter(&vfs_miplist_mutex); |
|
3128 |
if (vfs_miplist_end != NULL) |
|
3129 |
vfs_miplist_end->mip_next = mipp; |
|
3130 |
else |
|
3131 |
vfs_miplist = mipp; |
|
3132 |
vfs_miplist_end = mipp; |
|
3133 |
mutex_exit(&vfs_miplist_mutex); |
|
3134 |
} |
|
3135 |
||
3136 |
/* |
|
3137 |
* Called to remove an entry from the mount in progress list |
|
3138 |
* Either because the mount completed or it failed. |
|
3139 |
*/ |
|
3140 |
void |
|
3141 |
vfs_delmip(struct vfs *vfsp) |
|
3142 |
{ |
|
3143 |
struct ipmnt *mipp, *mipprev; |
|
3144 |
||
3145 |
mutex_enter(&vfs_miplist_mutex); |
|
3146 |
mipprev = NULL; |
|
3147 |
for (mipp = vfs_miplist; |
|
3912 | 3148 |
mipp && mipp->mip_vfsp != vfsp; mipp = mipp->mip_next) { |
0 | 3149 |
mipprev = mipp; |
3150 |
} |
|
3151 |
if (mipp == NULL) |
|
3152 |
return; /* shouldn't happen */ |
|
3153 |
if (mipp == vfs_miplist_end) |
|
3154 |
vfs_miplist_end = mipprev; |
|
3155 |
if (mipprev == NULL) |
|
3156 |
vfs_miplist = mipp->mip_next; |
|
3157 |
else |
|
3158 |
mipprev->mip_next = mipp->mip_next; |
|
3159 |
mutex_exit(&vfs_miplist_mutex); |
|
3160 |
kmem_free(mipp, sizeof (struct ipmnt)); |
|
3161 |
} |
|
3162 |
||
3163 |
/* |
|
3164 |
* vfs_add is called by a specific filesystem's mount routine to add |
|
3165 |
* the new vfs into the vfs list/hash and to cover the mounted-on vnode. |
|
3166 |
* The vfs should already have been locked by the caller. |
|
3167 |
* |
|
3168 |
* coveredvp is NULL if this is the root. |
|
3169 |
*/ |
|
3170 |
void |
|
3171 |
vfs_add(vnode_t *coveredvp, struct vfs *vfsp, int mflag) |
|
3172 |
{ |
|
3173 |
int newflag; |
|
3174 |
||
3175 |
ASSERT(vfs_lock_held(vfsp)); |
|
3176 |
VFS_HOLD(vfsp); |
|
3177 |
newflag = vfsp->vfs_flag; |
|
3178 |
if (mflag & MS_RDONLY) |
|
3179 |
newflag |= VFS_RDONLY; |
|
3180 |
else |
|
3181 |
newflag &= ~VFS_RDONLY; |
|
3182 |
if (mflag & MS_NOSUID) |
|
3183 |
newflag |= (VFS_NOSETUID|VFS_NODEVICES); |
|
3184 |
else |
|
3185 |
newflag &= ~(VFS_NOSETUID|VFS_NODEVICES); |
|
3186 |
if (mflag & MS_NOMNTTAB) |
|
3187 |
newflag |= VFS_NOMNTTAB; |
|
3188 |
else |
|
3189 |
newflag &= ~VFS_NOMNTTAB; |
|
3190 |
||
3191 |
if (coveredvp != NULL) { |
|
3192 |
ASSERT(vn_vfswlock_held(coveredvp)); |
|
3193 |
coveredvp->v_vfsmountedhere = vfsp; |
|
3194 |
VN_HOLD(coveredvp); |
|
3195 |
} |
|
3196 |
vfsp->vfs_vnodecovered = coveredvp; |
|
3197 |
vfsp->vfs_flag = newflag; |
|
3198 |
||
3199 |
vfs_list_add(vfsp); |
|
3200 |
} |
|
3201 |
||
3202 |
/* |
|
3203 |
* Remove a vfs from the vfs list, null out the pointer from the |
|
3204 |
* covered vnode to the vfs (v_vfsmountedhere), and null out the pointer |
|
3205 |
* from the vfs to the covered vnode (vfs_vnodecovered). Release the |
|
3206 |
* reference to the vfs and to the covered vnode. |
|
3207 |
* |
|
3208 |
* Called from dounmount after it's confirmed with the file system |
|
3209 |
* that the unmount is legal. |
|
3210 |
*/ |
|
3211 |
void |
|
3212 |
vfs_remove(struct vfs *vfsp) |
|
3213 |
{ |
|
3214 |
vnode_t *vp; |
|
3215 |
||
3216 |
ASSERT(vfs_lock_held(vfsp)); |
|
3217 |
||
3218 |
/* |
|
3219 |
* Can't unmount root. Should never happen because fs will |
|
3220 |
* be busy. |
|
3221 |
*/ |
|
3222 |
if (vfsp == rootvfs) |
|
3446 | 3223 |
panic("vfs_remove: unmounting root"); |
0 | 3224 |
|
3225 |
vfs_list_remove(vfsp); |
|
3226 |
||
3227 |
/* |
|
3228 |
* Unhook from the file system name space. |
|
3229 |
*/ |
|
3230 |
vp = vfsp->vfs_vnodecovered; |
|
3231 |
ASSERT(vn_vfswlock_held(vp)); |
|
3232 |
vp->v_vfsmountedhere = NULL; |
|
3233 |
vfsp->vfs_vnodecovered = NULL; |
|
3234 |
VN_RELE(vp); |
|
3235 |
||
3236 |
/* |
|
3237 |
* Release lock and wakeup anybody waiting. |
|
3238 |
*/ |
|
3239 |
vfs_unlock(vfsp); |
|
3240 |
VFS_RELE(vfsp); |
|
3241 |
} |
|
3242 |
||
3243 |
/* |
|
3244 |
* Lock a filesystem to prevent access to it while mounting, |
|
3245 |
* unmounting and syncing. Return EBUSY immediately if lock |
|
3246 |
* can't be acquired. |
|
3247 |
*/ |
|
3248 |
int |
|
3249 |
vfs_lock(vfs_t *vfsp) |
|
3250 |
{ |
|
3251 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3252 |
||
3253 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3254 |
if (rwst_tryenter(&vpvfsentry->ve_lock, RW_WRITER)) |
|
3255 |
return (0); |
|
3256 |
||
3257 |
vn_vfslocks_rele(vpvfsentry); |
|
3258 |
return (EBUSY); |
|
3259 |
} |
|
3260 |
||
3261 |
int |
|
3262 |
vfs_rlock(vfs_t *vfsp) |
|
3263 |
{ |
|
3264 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3265 |
||
3266 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3267 |
||
3268 |
if (rwst_tryenter(&vpvfsentry->ve_lock, RW_READER)) |
|
3269 |
return (0); |
|
3270 |
||
3271 |
vn_vfslocks_rele(vpvfsentry); |
|
3272 |
return (EBUSY); |
|
3273 |
} |
|
3274 |
||
3275 |
void |
|
3276 |
vfs_lock_wait(vfs_t *vfsp) |
|
3277 |
{ |
|
3278 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3279 |
||
3280 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3281 |
rwst_enter(&vpvfsentry->ve_lock, RW_WRITER); |
|
3282 |
} |
|
3283 |
||
3284 |
void |
|
3285 |
vfs_rlock_wait(vfs_t *vfsp) |
|
3286 |
{ |
|
3287 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3288 |
||
3289 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3290 |
rwst_enter(&vpvfsentry->ve_lock, RW_READER); |
|
3291 |
} |
|
3292 |
||
3293 |
/* |
|
3294 |
* Unlock a locked filesystem. |
|
3295 |
*/ |
|
3296 |
void |
|
3297 |
vfs_unlock(vfs_t *vfsp) |
|
3298 |
{ |
|
3299 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3300 |
||
3301 |
/* |
|
3302 |
* vfs_unlock will mimic sema_v behaviour to fix 4748018. |
|
3303 |
* And these changes should remain for the patch changes as it is. |
|
3304 |
*/ |
|
3305 |
if (panicstr) |
|
3306 |
return; |
|
3307 |
||
3308 |
/* |
|
3309 |
* ve_refcount needs to be dropped twice here. |
|
3310 |
* 1. To release refernce after a call to vfs_locks_getlock() |
|
3311 |
* 2. To release the reference from the locking routines like |
|
3312 |
* vfs_rlock_wait/vfs_wlock_wait/vfs_wlock etc,. |
|
3313 |
*/ |
|
3314 |
||
3315 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3316 |
vn_vfslocks_rele(vpvfsentry); |
|
3317 |
||
3318 |
rwst_exit(&vpvfsentry->ve_lock); |
|
3319 |
vn_vfslocks_rele(vpvfsentry); |
|
3320 |
} |
|
3321 |
||
3322 |
/* |
|
3323 |
* Utility routine that allows a filesystem to construct its |
|
3324 |
* fsid in "the usual way" - by munging some underlying dev_t and |
|
3325 |
* the filesystem type number into the 64-bit fsid. Note that |
|
3326 |
* this implicitly relies on dev_t persistence to make filesystem |
|
3327 |
* id's persistent. |
|
3328 |
* |
|
3329 |
* There's nothing to prevent an individual fs from constructing its |
|
3330 |
* fsid in a different way, and indeed they should. |
|
3331 |
* |
|
3332 |
* Since we want fsids to be 32-bit quantities (so that they can be |
|
3333 |
* exported identically by either 32-bit or 64-bit APIs, as well as |
|
3334 |
* the fact that fsid's are "known" to NFS), we compress the device |
|
3335 |
* number given down to 32-bits, and panic if that isn't possible. |
|
3336 |
*/ |
|
3337 |
void |
|
3338 |
vfs_make_fsid(fsid_t *fsi, dev_t dev, int val) |
|
3339 |
{ |
|
3340 |
if (!cmpldev((dev32_t *)&fsi->val[0], dev)) |
|
3341 |
panic("device number too big for fsid!"); |
|
3342 |
fsi->val[1] = val; |
|
3343 |
} |
|
3344 |
||
3345 |
int |
|
3346 |
vfs_lock_held(vfs_t *vfsp) |
|
3347 |
{ |
|
3348 |
int held; |
|
3349 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3350 |
||
3351 |
/* |
|
3352 |
* vfs_lock_held will mimic sema_held behaviour |
|
3353 |
* if panicstr is set. And these changes should remain |
|
3354 |
* for the patch changes as it is. |
|
3355 |
*/ |
|
3356 |
if (panicstr) |
|
3357 |
return (1); |
|
3358 |
||
3359 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3360 |
held = rwst_lock_held(&vpvfsentry->ve_lock, RW_WRITER); |
|
3361 |
||
3362 |
vn_vfslocks_rele(vpvfsentry); |
|
3363 |
return (held); |
|
3364 |
} |
|
3365 |
||
3366 |
struct _kthread * |
|
3367 |
vfs_lock_owner(vfs_t *vfsp) |
|
3368 |
{ |
|
3369 |
struct _kthread *owner; |
|
3370 |
vn_vfslocks_entry_t *vpvfsentry; |
|
3371 |
||
3372 |
/* |
|
3373 |
* vfs_wlock_held will mimic sema_held behaviour |
|
3374 |
* if panicstr is set. And these changes should remain |
|
3375 |
* for the patch changes as it is. |
|
3376 |
*/ |
|
3377 |
if (panicstr) |
|
3378 |
return (NULL); |
|
3379 |
||
3380 |
vpvfsentry = vn_vfslocks_getlock(vfsp); |
|
3381 |
owner = rwst_owner(&vpvfsentry->ve_lock); |
|
3382 |
||
3383 |
vn_vfslocks_rele(vpvfsentry); |
|
3384 |
return (owner); |
|
3385 |
} |
|
3386 |
||
3387 |
/* |
|
3388 |
* vfs list locking. |
|
3389 |
* |
|
3390 |
* Rather than manipulate the vfslist lock directly, we abstract into lock |
|
3391 |
* and unlock routines to allow the locking implementation to be changed for |
|
3392 |
* clustering. |
|
3393 |
* |
|
3394 |
* Whenever the vfs list is modified through its hash links, the overall list |
|
3395 |
* lock must be obtained before locking the relevant hash bucket. But to see |
|
3396 |
* whether a given vfs is on the list, it suffices to obtain the lock for the |
|
3397 |
* hash bucket without getting the overall list lock. (See getvfs() below.) |
|
3398 |
*/ |
|
3399 |
||
3400 |
void |
|
3401 |
vfs_list_lock() |
|
3402 |
{ |
|
3403 |
rw_enter(&vfslist, RW_WRITER); |
|
3404 |
} |
|
3405 |
||
3406 |
void |
|
3407 |
vfs_list_read_lock() |
|
3408 |
{ |
|
3409 |
rw_enter(&vfslist, RW_READER); |
|
3410 |
} |
|
3411 |
||
3412 |
void |
|
3413 |
vfs_list_unlock() |
|
3414 |
{ |
|
3415 |
rw_exit(&vfslist); |
|
3416 |
} |
|
3417 |
||
3418 |
/* |
|
3419 |
* Low level worker routines for adding entries to and removing entries from |
|
3420 |
* the vfs list. |
|
3421 |
*/ |
|
3422 |
||
3423 |
static void |
|
3424 |
vfs_hash_add(struct vfs *vfsp, int insert_at_head) |
|
3425 |
{ |
|
3426 |
int vhno; |
|
3427 |
struct vfs **hp; |
|
3428 |
dev_t dev; |
|
3429 |
||
3430 |
ASSERT(RW_WRITE_HELD(&vfslist)); |
|
3431 |
||
3432 |
dev = expldev(vfsp->vfs_fsid.val[0]); |
|
3433 |
vhno = VFSHASH(getmajor(dev), getminor(dev)); |
|
3434 |
||
3435 |
mutex_enter(&rvfs_list[vhno].rvfs_lock); |
|
3436 |
||
3437 |
/* |
|
3438 |
* Link into the hash table, inserting it at the end, so that LOFS |
|
3439 |
* with the same fsid as UFS (or other) file systems will not hide the |
|
3440 |
* UFS. |
|
3441 |
*/ |
|
3442 |
if (insert_at_head) { |
|
3443 |
vfsp->vfs_hash = rvfs_list[vhno].rvfs_head; |
|
3444 |
rvfs_list[vhno].rvfs_head = vfsp; |
|
3445 |
} else { |
|
3446 |
for (hp = &rvfs_list[vhno].rvfs_head; *hp != NULL; |
|
3447 |
hp = &(*hp)->vfs_hash) |
|
3448 |
continue; |
|
3449 |
/* |
|
3450 |
* hp now contains the address of the pointer to update |
|
3451 |
* to effect the insertion. |
|
3452 |
*/ |
|
3453 |
vfsp->vfs_hash = NULL; |
|
3454 |
*hp = vfsp; |
|
3455 |
} |
|
3456 |
||
3457 |
rvfs_list[vhno].rvfs_len++; |
|
3458 |
mutex_exit(&rvfs_list[vhno].rvfs_lock); |
|
3459 |
} |
|
3460 |
||
3461 |
||
3462 |
static void |
|
3463 |
vfs_hash_remove(struct vfs *vfsp) |
|
3464 |
{ |
|
3465 |
int vhno; |
|
3466 |
struct vfs *tvfsp; |
|
3467 |
dev_t dev; |
|
3468 |
||
3469 |
ASSERT(RW_WRITE_HELD(&vfslist)); |
|
3470 |
||
3471 |
dev = expldev(vfsp->vfs_fsid.val[0]); |
|
3472 |
vhno = VFSHASH(getmajor(dev), getminor(dev)); |
|
3473 |
||
3474 |
mutex_enter(&rvfs_list[vhno].rvfs_lock); |
|
3475 |
||
3476 |
/* |
|
3477 |
* Remove from hash. |
|
3478 |
*/ |
|
3479 |
if (rvfs_list[vhno].rvfs_head == vfsp) { |
|
3480 |
rvfs_list[vhno].rvfs_head = vfsp->vfs_hash; |
|
3481 |
rvfs_list[vhno].rvfs_len--; |
|
3482 |
goto foundit; |
|
3483 |
} |
|
3484 |
for (tvfsp = rvfs_list[vhno].rvfs_head; tvfsp != NULL; |
|
3485 |
tvfsp = tvfsp->vfs_hash) { |
|
3486 |
if (tvfsp->vfs_hash == vfsp) { |
|
3487 |
tvfsp->vfs_hash = vfsp->vfs_hash; |
|
3488 |
rvfs_list[vhno].rvfs_len--; |
|
3489 |
goto foundit; |
|
3490 |
} |
|
3491 |
} |
|
3492 |
cmn_err(CE_WARN, "vfs_list_remove: vfs not found in hash"); |
|
3493 |
||
3494 |
foundit: |
|
3495 |
||
3496 |
mutex_exit(&rvfs_list[vhno].rvfs_lock); |
|
3497 |
} |
|
3498 |
||
3499 |
||
3500 |
void |
|
3501 |
vfs_list_add(struct vfs *vfsp) |
|
3502 |
{ |
|
3503 |
zone_t *zone; |
|
3504 |
||
3505 |
/* |
|
10910
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3506 |
* Typically, the vfs_t will have been created on behalf of the file |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3507 |
* system in vfs_init, where it will have been provided with a |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3508 |
* vfs_impl_t. This, however, might be lacking if the vfs_t was created |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3509 |
* by an unbundled file system. We therefore check for such an example |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3510 |
* before stamping the vfs_t with its creation time for the benefit of |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3511 |
* mntfs. |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3512 |
*/ |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3513 |
if (vfsp->vfs_implp == NULL) |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3514 |
vfsimpl_setup(vfsp); |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3515 |
vfs_mono_time(&vfsp->vfs_hrctime); |
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3516 |
|
951a65b3846b
PSARC/2009/566 Provide minor private interface modifications to support mntfs
Robert Harris <Robert.Harris@Sun.COM>
parents:
10822
diff
changeset
|
3517 |
/* |
0 | 3518 |
* The zone that owns the mount is the one that performed the mount. |
3519 |
* Note that this isn't necessarily the same as the zone mounted into. |
|
13108
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
3520 |
* The corresponding zone_rele_ref() will be done when the vfs_t |
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
3521 |
* is being free'd. |
0 | 3522 |
*/ |
3523 |
vfsp->vfs_zone = curproc->p_zone; |
|
13108
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
3524 |
zone_init_ref(&vfsp->vfs_implp->vi_zone_ref); |
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
3525 |
zone_hold_ref(vfsp->vfs_zone, &vfsp->vfs_implp->vi_zone_ref, |
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
3526 |
ZONE_REF_VFS); |
0 | 3527 |
|
3528 |
/* |
|
3529 |
* Find the zone mounted into, and put this mount on its vfs list. |
|
3530 |
*/ |
|
3531 |
zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); |
|
3532 |
ASSERT(zone != NULL); |
|
3533 |
/* |
|
3534 |
* Special casing for the root vfs. This structure is allocated |
|
3535 |
* statically and hooked onto rootvfs at link time. During the |
|
3536 |
* vfs_mountroot call at system startup time, the root file system's |
|
3537 |
* VFS_MOUNTROOT routine will call vfs_add with this root vfs struct |
|
3538 |
* as argument. The code below must detect and handle this special |
|
3539 |
* case. The only apparent justification for this special casing is |
|
3540 |
* to ensure that the root file system appears at the head of the |
|
3541 |
* list. |
|
3542 |
* |
|
3543 |
* XXX: I'm assuming that it's ok to do normal list locking when |
|
3544 |
* adding the entry for the root file system (this used to be |
|
3545 |
* done with no locks held). |
|
3546 |
*/ |
|
3547 |
vfs_list_lock(); |
|
3548 |
/* |
|
3549 |
* Link into the vfs list proper. |
|
3550 |
*/ |
|
3551 |
if (vfsp == &root) { |
|
3552 |
/* |
|
3553 |
* Assert: This vfs is already on the list as its first entry. |
|
3554 |
* Thus, there's nothing to do. |
|
3555 |
*/ |
|
3556 |
ASSERT(rootvfs == vfsp); |
|
3557 |
/* |
|
3558 |
* Add it to the head of the global zone's vfslist. |
|
3559 |
*/ |
|
3560 |
ASSERT(zone == global_zone); |
|
3561 |
ASSERT(zone->zone_vfslist == NULL); |
|
3562 |
zone->zone_vfslist = vfsp; |
|
3563 |
} else { |
|
3564 |
/* |
|
3565 |
* Link to end of list using vfs_prev (as rootvfs is now a |
|
3566 |
* doubly linked circular list) so list is in mount order for |
|
3567 |
* mnttab use. |
|
3568 |
*/ |
|
3569 |
rootvfs->vfs_prev->vfs_next = vfsp; |
|
3570 |
vfsp->vfs_prev = rootvfs->vfs_prev; |
|
3571 |
rootvfs->vfs_prev = vfsp; |
|
3572 |
vfsp->vfs_next = rootvfs; |
|
3573 |
||
3574 |
/* |
|
3575 |
* Do it again for the zone-private list (which may be NULL). |
|
3576 |
*/ |
|
3577 |
if (zone->zone_vfslist == NULL) { |
|
3578 |
ASSERT(zone != global_zone); |
|
3579 |
zone->zone_vfslist = vfsp; |
|
3580 |
} else { |
|
3581 |
zone->zone_vfslist->vfs_zone_prev->vfs_zone_next = vfsp; |
|
3582 |
vfsp->vfs_zone_prev = zone->zone_vfslist->vfs_zone_prev; |
|
3583 |
zone->zone_vfslist->vfs_zone_prev = vfsp; |
|
3584 |
vfsp->vfs_zone_next = zone->zone_vfslist; |
|
3585 |
} |
|
3586 |
} |
|
3587 |
||
3588 |
/* |
|
3589 |
* Link into the hash table, inserting it at the end, so that LOFS |
|
3590 |
* with the same fsid as UFS (or other) file systems will not hide |
|
3591 |
* the UFS. |
|
3592 |
*/ |
|
3593 |
vfs_hash_add(vfsp, 0); |
|
3594 |
||
3595 |
/* |
|
3596 |
* update the mnttab modification time |
|
3597 |
*/ |
|
3598 |
vfs_mnttab_modtimeupd(); |
|
3599 |
vfs_list_unlock(); |
|
3600 |
zone_rele(zone); |
|
3601 |
} |
|
3602 |
||
3603 |
void |
|
3604 |
vfs_list_remove(struct vfs *vfsp) |
|
3605 |
{ |
|
3606 |
zone_t *zone; |
|
3607 |
||
3608 |
zone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt)); |
|
3609 |
ASSERT(zone != NULL); |
|
3610 |
/* |
|
3611 |
* Callers are responsible for preventing attempts to unmount the |
|
3612 |
* root. |
|
3613 |
*/ |
|
3614 |
ASSERT(vfsp != rootvfs); |
|
3615 |
||
3616 |
vfs_list_lock(); |
|
3617 |
||
3618 |
/* |
|
3619 |
* Remove from hash. |
|
3620 |
*/ |
|
3621 |
vfs_hash_remove(vfsp); |
|
3622 |
||
3623 |
/* |
|
3624 |
* Remove from vfs list. |
|
3625 |
*/ |
|
3626 |
vfsp->vfs_prev->vfs_next = vfsp->vfs_next; |
|
3627 |
vfsp->vfs_next->vfs_prev = vfsp->vfs_prev; |
|
3628 |
vfsp->vfs_next = vfsp->vfs_prev = NULL; |
|
3629 |
||
3630 |
/* |
|
3631 |
* Remove from zone-specific vfs list. |
|
3632 |
*/ |
|
3633 |
if (zone->zone_vfslist == vfsp) |
|
3634 |
zone->zone_vfslist = vfsp->vfs_zone_next; |
|
3635 |
||
3636 |
if (vfsp->vfs_zone_next == vfsp) { |
|
3637 |
ASSERT(vfsp->vfs_zone_prev == vfsp); |
|
3638 |
ASSERT(zone->zone_vfslist == vfsp); |
|
3639 |
zone->zone_vfslist = NULL; |
|
3640 |
} |
|
3641 |
||
3642 |
vfsp->vfs_zone_prev->vfs_zone_next = vfsp->vfs_zone_next; |
|
3643 |
vfsp->vfs_zone_next->vfs_zone_prev = vfsp->vfs_zone_prev; |
|
3644 |
vfsp->vfs_zone_next = vfsp->vfs_zone_prev = NULL; |
|
3645 |
||
3646 |
/* |
|
3647 |
* update the mnttab modification time |
|
3648 |
*/ |
|
3649 |
vfs_mnttab_modtimeupd(); |
|
3650 |
vfs_list_unlock(); |
|
3651 |
zone_rele(zone); |
|
3652 |
} |
|
3653 |
||
3654 |
struct vfs * |
|
3655 |
getvfs(fsid_t *fsid) |
|
3656 |
{ |
|
3657 |
struct vfs *vfsp; |
|
3658 |
int val0 = fsid->val[0]; |
|
3659 |
int val1 = fsid->val[1]; |
|
3660 |
dev_t dev = expldev(val0); |
|
3661 |
int vhno = VFSHASH(getmajor(dev), getminor(dev)); |
|
3662 |
kmutex_t *hmp = &rvfs_list[vhno].rvfs_lock; |
|
3663 |
||
3664 |
mutex_enter(hmp); |
|
3665 |
for (vfsp = rvfs_list[vhno].rvfs_head; vfsp; vfsp = vfsp->vfs_hash) { |
|
3666 |
if (vfsp->vfs_fsid.val[0] == val0 && |
|
3667 |
vfsp->vfs_fsid.val[1] == val1) { |
|
3668 |
VFS_HOLD(vfsp); |
|
3669 |
mutex_exit(hmp); |
|
3670 |
return (vfsp); |
|
3671 |
} |
|
3672 |
} |
|
3673 |
mutex_exit(hmp); |
|
3674 |
return (NULL); |
|
3675 |
} |
|
3676 |
||
3677 |
/* |
|
3678 |
* Search the vfs mount in progress list for a specified device/vfs entry. |
|
3679 |
* Returns 0 if the first entry in the list that the device matches has the |
|
3680 |
* given vfs pointer as well. If the device matches but a different vfs |
|
3681 |
* pointer is encountered in the list before the given vfs pointer then |
|
3682 |
* a 1 is returned. |
|
3683 |
*/ |
|
3684 |
||
3685 |
int |
|
3686 |
vfs_devmounting(dev_t dev, struct vfs *vfsp) |
|
3687 |
{ |
|
3688 |
int retval = 0; |
|
3689 |
struct ipmnt *mipp; |
|
3690 |
||
3691 |
mutex_enter(&vfs_miplist_mutex); |
|
3692 |
for (mipp = vfs_miplist; mipp != NULL; mipp = mipp->mip_next) { |
|
3693 |
if (mipp->mip_dev == dev) { |
|
3694 |
if (mipp->mip_vfsp != vfsp) |
|
3695 |
retval = 1; |
|
3696 |
break; |
|
3697 |
} |
|
3698 |
} |
|
3699 |
mutex_exit(&vfs_miplist_mutex); |
|
3700 |
return (retval); |
|
3701 |
} |
|
3702 |
||
3703 |
/* |
|
3704 |
* Search the vfs list for a specified device. Returns 1, if entry is found |
|
3705 |
* or 0 if no suitable entry is found. |
|
3706 |
*/ |
|
3707 |
||
3708 |
int |
|
3709 |
vfs_devismounted(dev_t dev) |
|
3710 |
{ |
|
3711 |
struct vfs *vfsp; |
|
3712 |
int found; |
|
3713 |
||
3714 |
vfs_list_read_lock(); |
|
3715 |
vfsp = rootvfs; |
|
3716 |
found = 0; |
|
3717 |
do { |
|
3718 |
if (vfsp->vfs_dev == dev) { |
|
3719 |
found = 1; |
|
3720 |
break; |
|
3721 |
} |
|
3722 |
vfsp = vfsp->vfs_next; |
|
3723 |
} while (vfsp != rootvfs); |
|
3724 |
||
3725 |
vfs_list_unlock(); |
|
3726 |
return (found); |
|
3727 |
} |
|
3728 |
||
3729 |
/* |
|
3730 |
* Search the vfs list for a specified device. Returns a pointer to it |
|
3731 |
* or NULL if no suitable entry is found. The caller of this routine |
|
3732 |
* is responsible for releasing the returned vfs pointer. |
|
3733 |
*/ |
|
3734 |
struct vfs * |
|
3735 |
vfs_dev2vfsp(dev_t dev) |
|
3736 |
{ |
|
3737 |
struct vfs *vfsp; |
|
3738 |
int found; |
|
3739 |
||
3740 |
vfs_list_read_lock(); |
|
3741 |
vfsp = rootvfs; |
|
3742 |
found = 0; |
|
3743 |
do { |
|
3744 |
/* |
|
3745 |
* The following could be made more efficient by making |
|
3746 |
* the entire loop use vfs_zone_next if the call is from |
|
3747 |
* a zone. The only callers, however, ustat(2) and |
|
3748 |
* umount2(2), don't seem to justify the added |
|
3749 |
* complexity at present. |
|
3750 |
*/ |
|
3751 |
if (vfsp->vfs_dev == dev && |
|
3752 |
ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt), |
|
3753 |
curproc->p_zone)) { |
|
3754 |
VFS_HOLD(vfsp); |
|
3755 |
found = 1; |
|
3756 |
break; |
|
3757 |
} |
|
3758 |
vfsp = vfsp->vfs_next; |
|
3759 |
} while (vfsp != rootvfs); |
|
3760 |
vfs_list_unlock(); |
|
3761 |
return (found ? vfsp: NULL); |
|
3762 |
} |
|
3763 |
||
3764 |
/* |
|
3765 |
* Search the vfs list for a specified mntpoint. Returns a pointer to it |
|
3766 |
* or NULL if no suitable entry is found. The caller of this routine |
|
3767 |
* is responsible for releasing the returned vfs pointer. |
|
3768 |
* |
|
3769 |
* Note that if multiple mntpoints match, the last one matching is |
|
3770 |
* returned in an attempt to return the "top" mount when overlay |
|
3771 |
* mounts are covering the same mount point. This is accomplished by starting |
|
3772 |
* at the end of the list and working our way backwards, stopping at the first |
|
3773 |
* matching mount. |
|
3774 |
*/ |
|
3775 |
struct vfs * |
|
3776 |
vfs_mntpoint2vfsp(const char *mp) |
|
3777 |
{ |
|
3778 |
struct vfs *vfsp; |
|
3779 |
struct vfs *retvfsp = NULL; |
|
3780 |
zone_t *zone = curproc->p_zone; |
|
3781 |
struct vfs *list; |
|
3782 |
||
3783 |
vfs_list_read_lock(); |
|
3784 |
if (getzoneid() == GLOBAL_ZONEID) { |
|
3785 |
/* |
|
3786 |
* The global zone may see filesystems in any zone. |
|
3787 |
*/ |
|
3788 |
vfsp = rootvfs->vfs_prev; |
|
3789 |
do { |
|
3790 |
if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) { |
|
3791 |
retvfsp = vfsp; |
|
3792 |
break; |
|
3793 |
} |
|
3794 |
vfsp = vfsp->vfs_prev; |
|
3795 |
} while (vfsp != rootvfs->vfs_prev); |
|
3796 |
} else if ((list = zone->zone_vfslist) != NULL) { |
|
3797 |
const char *mntpt; |
|
3798 |
||
3799 |
vfsp = list->vfs_zone_prev; |
|
3800 |
do { |
|
3801 |
mntpt = refstr_value(vfsp->vfs_mntpt); |
|
3802 |
mntpt = ZONE_PATH_TRANSLATE(mntpt, zone); |
|
3803 |
if (strcmp(mntpt, mp) == 0) { |
|
3804 |
retvfsp = vfsp; |
|
3805 |
break; |
|
3806 |
} |
|
3807 |
vfsp = vfsp->vfs_zone_prev; |
|
3808 |
} while (vfsp != list->vfs_zone_prev); |
|
3809 |
} |
|
3810 |
if (retvfsp) |
|
3811 |
VFS_HOLD(retvfsp); |
|
3812 |
vfs_list_unlock(); |
|
3813 |
return (retvfsp); |
|
3814 |
} |
|
3815 |
||
3816 |
/* |
|
3817 |
* Search the vfs list for a specified vfsops. |
|
3818 |
* if vfs entry is found then return 1, else 0. |
|
3819 |
*/ |
|
3820 |
int |
|
3821 |
vfs_opsinuse(vfsops_t *ops) |
|
3822 |
{ |
|
3823 |
struct vfs *vfsp; |
|
3824 |
int found; |
|
3825 |
||
3826 |
vfs_list_read_lock(); |
|
3827 |
vfsp = rootvfs; |
|
3828 |
found = 0; |
|
3829 |
do { |
|
3830 |
if (vfs_getops(vfsp) == ops) { |
|
3831 |
found = 1; |
|
3832 |
break; |
|
3833 |
} |
|
3834 |
vfsp = vfsp->vfs_next; |
|
3835 |
} while (vfsp != rootvfs); |
|
3836 |
vfs_list_unlock(); |
|
3837 |
return (found); |
|
3838 |
} |
|
3839 |
||
3840 |
/* |
|
3841 |
* Allocate an entry in vfssw for a file system type |
|
3842 |
*/ |
|
3843 |
struct vfssw * |
|
6855 | 3844 |
allocate_vfssw(const char *type) |
0 | 3845 |
{ |
3846 |
struct vfssw *vswp; |
|
3847 |
||
3848 |
if (type[0] == '\0' || strlen(type) + 1 > _ST_FSTYPSZ) { |
|
3849 |
/* |
|
3850 |
* The vfssw table uses the empty string to identify an |
|
3851 |
* available entry; we cannot add any type which has |
|
3852 |
* a leading NUL. The string length is limited to |
|
3853 |
* the size of the st_fstype array in struct stat. |
|
3854 |
*/ |
|
3855 |
return (NULL); |
|
3856 |
} |
|
3857 |
||
3858 |
ASSERT(VFSSW_WRITE_LOCKED()); |
|
3859 |
for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) |
|
3860 |
if (!ALLOCATED_VFSSW(vswp)) { |
|
3861 |
vswp->vsw_name = kmem_alloc(strlen(type) + 1, KM_SLEEP); |
|
3862 |
(void) strcpy(vswp->vsw_name, type); |
|
3863 |
ASSERT(vswp->vsw_count == 0); |
|
3864 |
vswp->vsw_count = 1; |
|
3865 |
mutex_init(&vswp->vsw_lock, NULL, MUTEX_DEFAULT, NULL); |
|
3866 |
return (vswp); |
|
3867 |
} |
|
3868 |
return (NULL); |
|
3869 |
} |
|
3870 |
||
3871 |
/* |
|
3872 |
* Impose additional layer of translation between vfstype names |
|
3873 |
* and module names in the filesystem. |
|
3874 |
*/ |
|
6855 | 3875 |
static const char * |
3876 |
vfs_to_modname(const char *vfstype) |
|
0 | 3877 |
{ |
3878 |
if (strcmp(vfstype, "proc") == 0) { |
|
3879 |
vfstype = "procfs"; |
|
3880 |
} else if (strcmp(vfstype, "fd") == 0) { |
|
3881 |
vfstype = "fdfs"; |
|
3882 |
} else if (strncmp(vfstype, "nfs", 3) == 0) { |
|
3883 |
vfstype = "nfs"; |
|
3884 |
} |
|
3885 |
||
3886 |
return (vfstype); |
|
3887 |
} |
|
3888 |
||
3889 |
/* |
|
3890 |
* Find a vfssw entry given a file system type name. |
|
3891 |
* Try to autoload the filesystem if it's not found. |
|
3892 |
* If it's installed, return the vfssw locked to prevent unloading. |
|
3893 |
*/ |
|
3894 |
struct vfssw * |
|
6855 | 3895 |
vfs_getvfssw(const char *type) |
0 | 3896 |
{ |
3897 |
struct vfssw *vswp; |
|
6855 | 3898 |
const char *modname; |
0 | 3899 |
|
3900 |
RLOCK_VFSSW(); |
|
3901 |
vswp = vfs_getvfsswbyname(type); |
|
3902 |
modname = vfs_to_modname(type); |
|
3903 |
||
3904 |
if (rootdir == NULL) { |
|
3905 |
/* |
|
3906 |
* If we haven't yet loaded the root file system, then our |
|
3907 |
* _init won't be called until later. Allocate vfssw entry, |
|
3908 |
* because mod_installfs won't be called. |
|
3909 |
*/ |
|
3910 |
if (vswp == NULL) { |
|
3911 |
RUNLOCK_VFSSW(); |
|
3912 |
WLOCK_VFSSW(); |
|
3913 |
if ((vswp = vfs_getvfsswbyname(type)) == NULL) { |
|
3914 |
if ((vswp = allocate_vfssw(type)) == NULL) { |
|
3915 |
WUNLOCK_VFSSW(); |
|
3916 |
return (NULL); |
|
3917 |
} |
|
3918 |
} |
|
3919 |
WUNLOCK_VFSSW(); |
|
3920 |
RLOCK_VFSSW(); |
|
3921 |
} |
|
3922 |
if (!VFS_INSTALLED(vswp)) { |
|
3923 |
RUNLOCK_VFSSW(); |
|
3924 |
(void) modloadonly("fs", modname); |
|
3925 |
} else |
|
3926 |
RUNLOCK_VFSSW(); |
|
3927 |
return (vswp); |
|
3928 |
} |
|
3929 |
||
3930 |
/* |
|
3931 |
* Try to load the filesystem. Before calling modload(), we drop |
|
3932 |
* our lock on the VFS switch table, and pick it up after the |
|
3933 |
* module is loaded. However, there is a potential race: the |
|
3934 |
* module could be unloaded after the call to modload() completes |
|
3935 |
* but before we pick up the lock and drive on. Therefore, |
|
3936 |
* we keep reloading the module until we've loaded the module |
|
3937 |
* _and_ we have the lock on the VFS switch table. |
|
3938 |
*/ |
|
3939 |
while (vswp == NULL || !VFS_INSTALLED(vswp)) { |
|
3940 |
RUNLOCK_VFSSW(); |
|
3941 |
if (modload("fs", modname) == -1) |
|
3942 |
return (NULL); |
|
3943 |
RLOCK_VFSSW(); |
|
3944 |
if (vswp == NULL) |
|
3945 |
if ((vswp = vfs_getvfsswbyname(type)) == NULL) |
|
3946 |
break; |
|
3947 |
} |
|
3948 |
RUNLOCK_VFSSW(); |
|
3949 |
||
3950 |
return (vswp); |
|
3951 |
} |
|
3952 |
||
3953 |
/* |
|
3954 |
* Find a vfssw entry given a file system type name. |
|
3955 |
*/ |
|
3956 |
struct vfssw * |
|
6855 | 3957 |
vfs_getvfsswbyname(const char *type) |
0 | 3958 |
{ |
3959 |
struct vfssw *vswp; |
|
3960 |
||
3961 |
ASSERT(VFSSW_LOCKED()); |
|
3962 |
if (type == NULL || *type == '\0') |
|
3963 |
return (NULL); |
|
3964 |
||
3965 |
for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { |
|
3966 |
if (strcmp(type, vswp->vsw_name) == 0) { |
|
3967 |
vfs_refvfssw(vswp); |
|
3968 |
return (vswp); |
|
3969 |
} |
|
3970 |
} |
|
3971 |
||
3972 |
return (NULL); |
|
3973 |
} |
|
3974 |
||
3975 |
/* |
|
3976 |
* Find a vfssw entry given a set of vfsops. |
|
3977 |
*/ |
|
3978 |
struct vfssw * |
|
3979 |
vfs_getvfsswbyvfsops(vfsops_t *vfsops) |
|
3980 |
{ |
|
3981 |
struct vfssw *vswp; |
|
3982 |
||
3983 |
RLOCK_VFSSW(); |
|
3984 |
for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { |
|
3985 |
if (ALLOCATED_VFSSW(vswp) && &vswp->vsw_vfsops == vfsops) { |
|
3986 |
vfs_refvfssw(vswp); |
|
3987 |
RUNLOCK_VFSSW(); |
|
3988 |
return (vswp); |
|
3989 |
} |
|
3990 |
} |
|
3991 |
RUNLOCK_VFSSW(); |
|
3992 |
||
3993 |
return (NULL); |
|
3994 |
} |
|
3995 |
||
3996 |
/* |
|
3997 |
* Reference a vfssw entry. |
|
3998 |
*/ |
|
3999 |
void |
|
4000 |
vfs_refvfssw(struct vfssw *vswp) |
|
4001 |
{ |
|
4002 |
||
4003 |
mutex_enter(&vswp->vsw_lock); |
|
4004 |
vswp->vsw_count++; |
|
4005 |
mutex_exit(&vswp->vsw_lock); |
|
4006 |
} |
|
4007 |
||
4008 |
/* |
|
4009 |
* Unreference a vfssw entry. |
|
4010 |
*/ |
|
4011 |
void |
|
4012 |
vfs_unrefvfssw(struct vfssw *vswp) |
|
4013 |
{ |
|
4014 |
||
4015 |
mutex_enter(&vswp->vsw_lock); |
|
4016 |
vswp->vsw_count--; |
|
4017 |
mutex_exit(&vswp->vsw_lock); |
|
4018 |
} |
|
4019 |
||
4020 |
int sync_timeout = 30; /* timeout for syncing a page during panic */ |
|
4021 |
int sync_timeleft; /* portion of sync_timeout remaining */ |
|
4022 |
||
4023 |
static int sync_retries = 20; /* number of retries when not making progress */ |
|
4024 |
static int sync_triesleft; /* portion of sync_retries remaining */ |
|
4025 |
||
4026 |
static pgcnt_t old_pgcnt, new_pgcnt; |
|
4027 |
static int new_bufcnt, old_bufcnt; |
|
4028 |
||
4029 |
/* |
|
4030 |
* Sync all of the mounted filesystems, and then wait for the actual i/o to |
|
4031 |
* complete. We wait by counting the number of dirty pages and buffers, |
|
4032 |
* pushing them out using bio_busy() and page_busy(), and then counting again. |
|
4033 |
* This routine is used during both the uadmin A_SHUTDOWN code as well as |
|
4034 |
* the SYNC phase of the panic code (see comments in panic.c). It should only |
|
4035 |
* be used after some higher-level mechanism has quiesced the system so that |
|
4036 |
* new writes are not being initiated while we are waiting for completion. |
|
4037 |
* |
|
4038 |
* To ensure finite running time, our algorithm uses two timeout mechanisms: |
|
4039 |
* sync_timeleft (a timer implemented by the omnipresent deadman() cyclic), and |
|
4040 |
* sync_triesleft (a progress counter used by the vfs_syncall() loop below). |
|
4041 |
* Together these ensure that syncing completes if our i/o paths are stuck. |
|
4042 |
* The counters are declared above so they can be found easily in the debugger. |
|
4043 |
* |
|
4044 |
* The sync_timeleft counter is reset by bio_busy() and page_busy() using the |
|
4045 |
* vfs_syncprogress() subroutine whenever we make progress through the lists of |
|
4046 |
* pages and buffers. It is decremented and expired by the deadman() cyclic. |
|
4047 |
* When vfs_syncall() decides it is done, we disable the deadman() counter by |
|
4048 |
* setting sync_timeleft to zero. This timer guards against vfs_syncall() |
|
4049 |
* deadlocking or hanging inside of a broken filesystem or driver routine. |
|
4050 |
* |
|
4051 |
* The sync_triesleft counter is updated by vfs_syncall() itself. If we make |
|
4052 |
* sync_retries consecutive calls to bio_busy() and page_busy() without |
|
4053 |
* decreasing either the number of dirty buffers or dirty pages below the |
|
4054 |
* lowest count we have seen so far, we give up and return from vfs_syncall(). |
|
4055 |
* |
|
4056 |
* Each loop iteration ends with a call to delay() one second to allow time for |
|
4057 |
* i/o completion and to permit the user time to read our progress messages. |
|
4058 |
*/ |
|
4059 |
void |
|
4060 |
vfs_syncall(void) |
|
4061 |
{ |
|
4062 |
if (rootdir == NULL && !modrootloaded) |
|
4063 |
return; /* panic during boot - no filesystems yet */ |
|
4064 |
||
4065 |
printf("syncing file systems..."); |
|
4066 |
vfs_syncprogress(); |
|
4067 |
sync(); |
|
4068 |
||
4069 |
vfs_syncprogress(); |
|
4070 |
sync_triesleft = sync_retries; |
|
4071 |
||
4072 |
old_bufcnt = new_bufcnt = INT_MAX; |
|
4073 |
old_pgcnt = new_pgcnt = ULONG_MAX; |
|
4074 |
||
4075 |
while (sync_triesleft > 0) { |
|
4076 |
old_bufcnt = MIN(old_bufcnt, new_bufcnt); |
|
4077 |
old_pgcnt = MIN(old_pgcnt, new_pgcnt); |
|
4078 |
||
4079 |
new_bufcnt = bio_busy(B_TRUE); |
|
4080 |
new_pgcnt = page_busy(B_TRUE); |
|
4081 |
vfs_syncprogress(); |
|
4082 |
||
4083 |
if (new_bufcnt == 0 && new_pgcnt == 0) |
|
4084 |
break; |
|
4085 |
||
4086 |
if (new_bufcnt < old_bufcnt || new_pgcnt < old_pgcnt) |
|
4087 |
sync_triesleft = sync_retries; |
|
4088 |
else |
|
4089 |
sync_triesleft--; |
|
4090 |
||
4091 |
if (new_bufcnt) |
|
4092 |
printf(" [%d]", new_bufcnt); |
|
4093 |
if (new_pgcnt) |
|
4094 |
printf(" %lu", new_pgcnt); |
|
4095 |
||
4096 |
delay(hz); |
|
4097 |
} |
|
4098 |
||
4099 |
if (new_bufcnt != 0 || new_pgcnt != 0) |
|
4100 |
printf(" done (not all i/o completed)\n"); |
|
4101 |
else |
|
4102 |
printf(" done\n"); |
|
4103 |
||
4104 |
sync_timeleft = 0; |
|
4105 |
delay(hz); |
|
4106 |
} |
|
4107 |
||
4108 |
/* |
|
4109 |
* If we are in the middle of the sync phase of panic, reset sync_timeleft to |
|
4110 |
* sync_timeout to indicate that we are making progress and the deadman() |
|
4111 |
* omnipresent cyclic should not yet time us out. Note that it is safe to |
|
4112 |
* store to sync_timeleft here since the deadman() is firing at high-level |
|
4113 |
* on top of us. If we are racing with the deadman(), either the deadman() |
|
4114 |
* will decrement the old value and then we will reset it, or we will |
|
4115 |
* reset it and then the deadman() will immediately decrement it. In either |
|
4116 |
* case, correct behavior results. |
|
4117 |
*/ |
|
4118 |
void |
|
4119 |
vfs_syncprogress(void) |
|
4120 |
{ |
|
4121 |
if (panicstr) |
|
4122 |
sync_timeleft = sync_timeout; |
|
4123 |
} |
|
4124 |
||
4125 |
/* |
|
4126 |
* Map VFS flags to statvfs flags. These shouldn't really be separate |
|
4127 |
* flags at all. |
|
4128 |
*/ |
|
4129 |
uint_t |
|
4130 |
vf_to_stf(uint_t vf) |
|
4131 |
{ |
|
4132 |
uint_t stf = 0; |
|
4133 |
||
4134 |
if (vf & VFS_RDONLY) |
|
4135 |
stf |= ST_RDONLY; |
|
4136 |
if (vf & VFS_NOSETUID) |
|
4137 |
stf |= ST_NOSUID; |
|
4138 |
if (vf & VFS_NOTRUNC) |
|
4139 |
stf |= ST_NOTRUNC; |
|
4140 |
||
4141 |
return (stf); |
|
4142 |
} |
|
4143 |
||
4144 |
/* |
|
4145 |
* Entries for (illegal) fstype 0. |
|
4146 |
*/ |
|
4147 |
/* ARGSUSED */ |
|
4148 |
int |
|
4149 |
vfsstray_sync(struct vfs *vfsp, short arg, struct cred *cr) |
|
4150 |
{ |
|
4151 |
cmn_err(CE_PANIC, "stray vfs operation"); |
|
4152 |
return (0); |
|
4153 |
} |
|
4154 |
||
4155 |
/* |
|
4156 |
* Entries for (illegal) fstype 0. |
|
4157 |
*/ |
|
4158 |
int |
|
4159 |
vfsstray(void) |
|
4160 |
{ |
|
4161 |
cmn_err(CE_PANIC, "stray vfs operation"); |
|
4162 |
return (0); |
|
4163 |
} |
|
4164 |
||
4165 |
/* |
|
4166 |
* Support for dealing with forced UFS unmount and its interaction with |
|
4167 |
* LOFS. Could be used by any filesystem. |
|
4168 |
* See bug 1203132. |
|
4169 |
*/ |
|
4170 |
int |
|
4171 |
vfs_EIO(void) |
|
4172 |
{ |
|
4173 |
return (EIO); |
|
4174 |
} |
|
4175 |
||
4176 |
/* |
|
4177 |
* We've gotta define the op for sync separately, since the compiler gets |
|
4178 |
* confused if we mix and match ANSI and normal style prototypes when |
|
4179 |
* a "short" argument is present and spits out a warning. |
|
4180 |
*/ |
|
4181 |
/*ARGSUSED*/ |
|
4182 |
int |
|
4183 |
vfs_EIO_sync(struct vfs *vfsp, short arg, struct cred *cr) |
|
4184 |
{ |
|
4185 |
return (EIO); |
|
4186 |
} |
|
4187 |
||
4188 |
vfs_t EIO_vfs; |
|
4189 |
vfsops_t *EIO_vfsops; |
|
4190 |
||
4191 |
/* |
|
4192 |
* Called from startup() to initialize all loaded vfs's |
|
4193 |
*/ |
|
4194 |
void |
|
4195 |
vfsinit(void) |
|
4196 |
{ |
|
4197 |
struct vfssw *vswp; |
|
4198 |
int error; |
|
1520 | 4199 |
extern int vopstats_enabled; |
1488 | 4200 |
extern void vopstats_startup(); |
0 | 4201 |
|
4202 |
static const fs_operation_def_t EIO_vfsops_template[] = { |
|
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4203 |
VFSNAME_MOUNT, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4204 |
VFSNAME_UNMOUNT, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4205 |
VFSNAME_ROOT, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4206 |
VFSNAME_STATVFS, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4207 |
VFSNAME_SYNC, { .vfs_sync = vfs_EIO_sync }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4208 |
VFSNAME_VGET, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4209 |
VFSNAME_MOUNTROOT, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4210 |
VFSNAME_FREEVFS, { .error = vfs_EIO }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4211 |
VFSNAME_VNSTATE, { .error = vfs_EIO }, |
0 | 4212 |
NULL, NULL |
4213 |
}; |
|
4214 |
||
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4215 |
static const fs_operation_def_t stray_vfsops_template[] = { |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4216 |
VFSNAME_MOUNT, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4217 |
VFSNAME_UNMOUNT, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4218 |
VFSNAME_ROOT, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4219 |
VFSNAME_STATVFS, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4220 |
VFSNAME_SYNC, { .vfs_sync = vfsstray_sync }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4221 |
VFSNAME_VGET, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4222 |
VFSNAME_MOUNTROOT, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4223 |
VFSNAME_FREEVFS, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4224 |
VFSNAME_VNSTATE, { .error = vfsstray }, |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4225 |
NULL, NULL |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4226 |
}; |
0 | 4227 |
|
5331 | 4228 |
/* Create vfs cache */ |
4229 |
vfs_cache = kmem_cache_create("vfs_cache", sizeof (struct vfs), |
|
4230 |
sizeof (uintptr_t), NULL, NULL, NULL, NULL, NULL, 0); |
|
4231 |
||
0 | 4232 |
/* Initialize the vnode cache (file systems may use it during init). */ |
4233 |
vn_create_cache(); |
|
4234 |
||
4235 |
/* Setup event monitor framework */ |
|
4236 |
fem_init(); |
|
4237 |
||
4238 |
/* Initialize the dummy stray file system type. */ |
|
3904 | 4239 |
error = vfs_setfsops(0, stray_vfsops_template, NULL); |
0 | 4240 |
|
4241 |
/* Initialize the dummy EIO file system. */ |
|
4242 |
error = vfs_makefsops(EIO_vfsops_template, &EIO_vfsops); |
|
4243 |
if (error != 0) { |
|
4244 |
cmn_err(CE_WARN, "vfsinit: bad EIO vfs ops template"); |
|
4245 |
/* Shouldn't happen, but not bad enough to panic */ |
|
4246 |
} |
|
4247 |
||
4248 |
VFS_INIT(&EIO_vfs, EIO_vfsops, (caddr_t)NULL); |
|
4249 |
||
4250 |
/* |
|
4251 |
* Default EIO_vfs.vfs_flag to VFS_UNMOUNTED so a lookup |
|
4252 |
* on this vfs can immediately notice it's invalid. |
|
4253 |
*/ |
|
4254 |
EIO_vfs.vfs_flag |= VFS_UNMOUNTED; |
|
4255 |
||
4256 |
/* |
|
4257 |
* Call the init routines of non-loadable filesystems only. |
|
4258 |
* Filesystems which are loaded as separate modules will be |
|
4259 |
* initialized by the module loading code instead. |
|
4260 |
*/ |
|
4261 |
||
4262 |
for (vswp = &vfssw[1]; vswp < &vfssw[nfstype]; vswp++) { |
|
4263 |
RLOCK_VFSSW(); |
|
4264 |
if (vswp->vsw_init != NULL) |
|
4265 |
(*vswp->vsw_init)(vswp - vfssw, vswp->vsw_name); |
|
4266 |
RUNLOCK_VFSSW(); |
|
4267 |
} |
|
1488 | 4268 |
|
4269 |
vopstats_startup(); |
|
1520 | 4270 |
|
4271 |
if (vopstats_enabled) { |
|
4272 |
/* EIO_vfs can collect stats, but we don't retrieve them */ |
|
4273 |
initialize_vopstats(&EIO_vfs.vfs_vopstats); |
|
4274 |
EIO_vfs.vfs_fstypevsp = NULL; |
|
4275 |
EIO_vfs.vfs_vskap = NULL; |
|
4276 |
EIO_vfs.vfs_flag |= VFS_STATS; |
|
4277 |
} |
|
5331 | 4278 |
|
4279 |
xattr_init(); |
|
10793
34709091de6d
6886081 Solaris needs reparse point support (PSARC 2009/387)
Dai Ngo <dai.ngo@sun.com>
parents:
8194
diff
changeset
|
4280 |
|
34709091de6d
6886081 Solaris needs reparse point support (PSARC 2009/387)
Dai Ngo <dai.ngo@sun.com>
parents:
8194
diff
changeset
|
4281 |
reparse_point_init(); |
5331 | 4282 |
} |
4283 |
||
4284 |
vfs_t * |
|
4285 |
vfs_alloc(int kmflag) |
|
4286 |
{ |
|
4287 |
vfs_t *vfsp; |
|
4288 |
||
4289 |
vfsp = kmem_cache_alloc(vfs_cache, kmflag); |
|
4290 |
||
4291 |
/* |
|
4292 |
* Do the simplest initialization here. |
|
4293 |
* Everything else gets done in vfs_init() |
|
4294 |
*/ |
|
4295 |
bzero(vfsp, sizeof (vfs_t)); |
|
4296 |
return (vfsp); |
|
4297 |
} |
|
4298 |
||
4299 |
void |
|
4300 |
vfs_free(vfs_t *vfsp) |
|
4301 |
{ |
|
4302 |
/* |
|
4303 |
* One would be tempted to assert that "vfsp->vfs_count == 0". |
|
4304 |
* The problem is that this gets called out of domount() with |
|
4305 |
* a partially initialized vfs and a vfs_count of 1. This is |
|
4306 |
* also called from vfs_rele() with a vfs_count of 0. We can't |
|
4307 |
* call VFS_RELE() from domount() if VFS_MOUNT() hasn't successfully |
|
4308 |
* returned. This is because VFS_MOUNT() fully initializes the |
|
4309 |
* vfs structure and its associated data. VFS_RELE() will call |
|
4310 |
* VFS_FREEVFS() which may panic the system if the data structures |
|
4311 |
* aren't fully initialized from a successful VFS_MOUNT()). |
|
4312 |
*/ |
|
4313 |
||
4314 |
/* If FEM was in use, make sure everything gets cleaned up */ |
|
4315 |
if (vfsp->vfs_femhead) { |
|
4316 |
ASSERT(vfsp->vfs_femhead->femh_list == NULL); |
|
4317 |
mutex_destroy(&vfsp->vfs_femhead->femh_lock); |
|
4318 |
kmem_free(vfsp->vfs_femhead, sizeof (*(vfsp->vfs_femhead))); |
|
4319 |
vfsp->vfs_femhead = NULL; |
|
4320 |
} |
|
4321 |
||
4322 |
if (vfsp->vfs_implp) |
|
4323 |
vfsimpl_teardown(vfsp); |
|
4324 |
sema_destroy(&vfsp->vfs_reflock); |
|
4325 |
kmem_cache_free(vfs_cache, vfsp); |
|
0 | 4326 |
} |
4327 |
||
4328 |
/* |
|
4329 |
* Increments the vfs reference count by one atomically. |
|
4330 |
*/ |
|
4331 |
void |
|
4332 |
vfs_hold(vfs_t *vfsp) |
|
4333 |
{ |
|
4334 |
atomic_add_32(&vfsp->vfs_count, 1); |
|
4335 |
ASSERT(vfsp->vfs_count != 0); |
|
4336 |
} |
|
4337 |
||
4338 |
/* |
|
4339 |
* Decrements the vfs reference count by one atomically. When |
|
4340 |
* vfs reference count becomes zero, it calls the file system |
|
4341 |
* specific vfs_freevfs() to free up the resources. |
|
4342 |
*/ |
|
4343 |
void |
|
4344 |
vfs_rele(vfs_t *vfsp) |
|
4345 |
{ |
|
4346 |
ASSERT(vfsp->vfs_count != 0); |
|
4347 |
if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 0) { |
|
4348 |
VFS_FREEVFS(vfsp); |
|
6734 | 4349 |
lofi_remove(vfsp); |
0 | 4350 |
if (vfsp->vfs_zone) |
13108
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
4351 |
zone_rele_ref(&vfsp->vfs_implp->vi_zone_ref, |
b02331b7b26d
6906740 Zones need an improved reference counting mechanism
jv227347 <Jordan.Vaughan@Sun.com>
parents:
12906
diff
changeset
|
4352 |
ZONE_REF_VFS); |
0 | 4353 |
vfs_freemnttab(vfsp); |
5331 | 4354 |
vfs_free(vfsp); |
0 | 4355 |
} |
4356 |
} |
|
4357 |
||
4358 |
/* |
|
4359 |
* Generic operations vector support. |
|
4360 |
* |
|
4361 |
* This is used to build operations vectors for both the vfs and vnode. |
|
4362 |
* It's normally called only when a file system is loaded. |
|
4363 |
* |
|
4364 |
* There are many possible algorithms for this, including the following: |
|
4365 |
* |
|
4366 |
* (1) scan the list of known operations; for each, see if the file system |
|
4367 |
* includes an entry for it, and fill it in as appropriate. |
|
4368 |
* |
|
4369 |
* (2) set up defaults for all known operations. scan the list of ops |
|
4370 |
* supplied by the file system; for each which is both supplied and |
|
4371 |
* known, fill it in. |
|
4372 |
* |
|
4373 |
* (3) sort the lists of known ops & supplied ops; scan the list, filling |
|
4374 |
* in entries as we go. |
|
4375 |
* |
|
4376 |
* we choose (1) for simplicity, and because performance isn't critical here. |
|
4377 |
* note that (2) could be sped up using a precomputed hash table on known ops. |
|
4378 |
* (3) could be faster than either, but only if the lists were very large or |
|
4379 |
* supplied in sorted order. |
|
4380 |
* |
|
4381 |
*/ |
|
4382 |
||
4383 |
int |
|
4384 |
fs_build_vector(void *vector, int *unused_ops, |
|
4385 |
const fs_operation_trans_def_t *translation, |
|
4386 |
const fs_operation_def_t *operations) |
|
4387 |
{ |
|
4388 |
int i, num_trans, num_ops, used; |
|
4389 |
||
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4390 |
/* |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4391 |
* Count the number of translations and the number of supplied |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4392 |
* operations. |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4393 |
*/ |
0 | 4394 |
|
4395 |
{ |
|
4396 |
const fs_operation_trans_def_t *p; |
|
4397 |
||
4398 |
for (num_trans = 0, p = translation; |
|
4399 |
p->name != NULL; |
|
4400 |
num_trans++, p++) |
|
4401 |
; |
|
4402 |
} |
|
4403 |
||
4404 |
{ |
|
4405 |
const fs_operation_def_t *p; |
|
4406 |
||
4407 |
for (num_ops = 0, p = operations; |
|
4408 |
p->name != NULL; |
|
4409 |
num_ops++, p++) |
|
4410 |
; |
|
4411 |
} |
|
4412 |
||
4413 |
/* Walk through each operation known to our caller. There will be */ |
|
4414 |
/* one entry in the supplied "translation table" for each. */ |
|
4415 |
||
4416 |
used = 0; |
|
4417 |
||
4418 |
for (i = 0; i < num_trans; i++) { |
|
4419 |
int j, found; |
|
4420 |
char *curname; |
|
4421 |
fs_generic_func_p result; |
|
4422 |
fs_generic_func_p *location; |
|
4423 |
||
4424 |
curname = translation[i].name; |
|
4425 |
||
4426 |
/* Look for a matching operation in the list supplied by the */ |
|
4427 |
/* file system. */ |
|
4428 |
||
4429 |
found = 0; |
|
4430 |
||
4431 |
for (j = 0; j < num_ops; j++) { |
|
4432 |
if (strcmp(operations[j].name, curname) == 0) { |
|
4433 |
used++; |
|
4434 |
found = 1; |
|
4435 |
break; |
|
4436 |
} |
|
4437 |
} |
|
4438 |
||
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4439 |
/* |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4440 |
* If the file system is using a "placeholder" for default |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4441 |
* or error functions, grab the appropriate function out of |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4442 |
* the translation table. If the file system didn't supply |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4443 |
* this operation at all, use the default function. |
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4444 |
*/ |
0 | 4445 |
|
4446 |
if (found) { |
|
3898
c788126f2a20
PSARC/2007/124 Strong Type-Checking for VFS Operation Registration Mechanism
rsb
parents:
3446
diff
changeset
|
4447 |
result = operations[j].func.fs_generic; |
0 | 4448 |
if (result == fs_default) { |
4449 |
result = translation[i].defaultFunc; |
|
4450 |
} else if (result == fs_error) { |
|
4451 |
result = translation[i].errorFunc; |
|
4452 |
} else if (result == NULL) { |
|
4453 |
/* Null values are PROHIBITED */ |
|
4454 |
return (EINVAL); |
|
4455 |
} |
|
4456 |
} else { |
|
4457 |
result = translation[i].defaultFunc; |
|
4458 |
} |
|
4459 |
||
4460 |
/* Now store the function into the operations vector. */ |
|
4461 |
||
4462 |
location = (fs_generic_func_p *) |
|
4463 |
(((char *)vector) + translation[i].offset); |
|
4464 |
||
4465 |
*location = result; |
|
4466 |
} |
|
4467 |
||
4468 |
*unused_ops = num_ops - used; |
|
4469 |
||
4470 |
return (0); |
|
4471 |
} |
|
4472 |
||
4473 |
/* Placeholder functions, should never be called. */ |
|
4474 |
||
4475 |
int |
|
4476 |
fs_error(void) |
|
4477 |
{ |
|
4478 |
cmn_err(CE_PANIC, "fs_error called"); |
|
4479 |
return (0); |
|
4480 |
} |
|
4481 |
||
4482 |
int |
|
4483 |
fs_default(void) |
|
4484 |
{ |
|
4485 |
cmn_err(CE_PANIC, "fs_default called"); |
|
4486 |
return (0); |
|
4487 |
} |
|
4488 |
||
4489 |
#ifdef __sparc |
|
4490 |
||
4491 |
/* |
|
4492 |
* Part of the implementation of booting off a mirrored root |
|
4493 |
* involves a change of dev_t for the root device. To |
|
4494 |
* accomplish this, first remove the existing hash table |
|
4495 |
* entry for the root device, convert to the new dev_t, |
|
4496 |
* then re-insert in the hash table at the head of the list. |
|
4497 |
*/ |
|
4498 |
void |
|
4499 |
vfs_root_redev(vfs_t *vfsp, dev_t ndev, int fstype) |
|
4500 |
{ |
|
4501 |
vfs_list_lock(); |
|
4502 |
||
4503 |
vfs_hash_remove(vfsp); |
|
4504 |
||
4505 |
vfsp->vfs_dev = ndev; |
|
4506 |
vfs_make_fsid(&vfsp->vfs_fsid, ndev, fstype); |
|
4507 |
||
4508 |
vfs_hash_add(vfsp, 1); |
|
4509 |
||
4510 |
vfs_list_unlock(); |
|
4511 |
} |
|
4512 |
||
4513 |
#else /* x86 NEWBOOT */ |
|
4514 |
||
6318
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4515 |
#if defined(__x86) |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4516 |
extern int hvmboot_rootconf(); |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4517 |
#endif /* __x86 */ |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4518 |
|
8194 | 4519 |
extern ib_boot_prop_t *iscsiboot_prop; |
4520 |
||
0 | 4521 |
int |
4522 |
rootconf() |
|
4523 |
{ |
|
4524 |
int error; |
|
4525 |
struct vfssw *vsw; |
|
4526 |
extern void pm_init(); |
|
5084 | 4527 |
char *fstyp, *fsmod; |
8194 | 4528 |
int ret = -1; |
5084 | 4529 |
|
4530 |
getrootfs(&fstyp, &fsmod); |
|
0 | 4531 |
|
6318
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4532 |
#if defined(__x86) |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4533 |
/* |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4534 |
* hvmboot_rootconf() is defined in the hvm_bootstrap misc module, |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4535 |
* which lives in /platform/i86hvm, and hence is only available when |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4536 |
* booted in an x86 hvm environment. If the hvm_bootstrap misc module |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4537 |
* is not available then the modstub for this function will return 0. |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4538 |
* If the hvm_bootstrap misc module is available it will be loaded |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4539 |
* and hvmboot_rootconf() will be invoked. |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4540 |
*/ |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4541 |
if (error = hvmboot_rootconf()) |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4542 |
return (error); |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4543 |
#endif /* __x86 */ |
1d4ab74726bc
PSARC/2007/664 Paravirtualized Drivers for Fully Virtualized xVM Domains
edp
parents:
6224
diff
changeset
|
4544 |
|
0 | 4545 |
if (error = clboot_rootconf()) |
4546 |
return (error); |
|
4547 |
||
5084 | 4548 |
if (modload("fs", fsmod) == -1) |
4549 |
panic("Cannot _init %s module", fsmod); |
|
0 | 4550 |
|
4551 |
RLOCK_VFSSW(); |
|
4552 |
vsw = vfs_getvfsswbyname(fstyp); |
|
4553 |
RUNLOCK_VFSSW(); |
|
7439
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4554 |
if (vsw == NULL) { |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4555 |
cmn_err(CE_CONT, "Cannot find %s filesystem\n", fstyp); |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4556 |
return (ENXIO); |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4557 |
} |
0 | 4558 |
VFS_INIT(rootvfs, &vsw->vsw_vfsops, 0); |
4559 |
VFS_HOLD(rootvfs); |
|
4560 |
||
4561 |
/* always mount readonly first */ |
|
4562 |
rootvfs->vfs_flag |= VFS_RDONLY; |
|
4563 |
||
4564 |
pm_init(); |
|
4565 |
||
8194 | 4566 |
if (netboot && iscsiboot_prop) { |
4567 |
cmn_err(CE_WARN, "NFS boot and iSCSI boot" |
|
4568 |
" shouldn't happen in the same time"); |
|
4569 |
return (EINVAL); |
|
4570 |
} |
|
4571 |
||
10822 | 4572 |
if (netboot || iscsiboot_prop) { |
8194 | 4573 |
ret = strplumb(); |
10822 | 4574 |
if (ret != 0) { |
4575 |
cmn_err(CE_WARN, "Cannot plumb network device %d", ret); |
|
4576 |
return (EFAULT); |
|
4577 |
} |
|
4578 |
} |
|
8194 | 4579 |
|
4580 |
if ((ret == 0) && iscsiboot_prop) { |
|
4581 |
ret = modload("drv", "iscsi"); |
|
4582 |
/* -1 indicates fail */ |
|
4583 |
if (ret == -1) { |
|
4584 |
cmn_err(CE_WARN, "Failed to load iscsi module"); |
|
4585 |
iscsi_boot_prop_free(); |
|
4586 |
return (EINVAL); |
|
4587 |
} else { |
|
4588 |
if (!i_ddi_attach_pseudo_node("iscsi")) { |
|
4589 |
cmn_err(CE_WARN, |
|
4590 |
"Failed to attach iscsi driver"); |
|
4591 |
iscsi_boot_prop_free(); |
|
4592 |
return (ENODEV); |
|
4593 |
} |
|
4594 |
} |
|
4595 |
} |
|
0 | 4596 |
|
4597 |
error = VFS_MOUNTROOT(rootvfs, ROOT_INIT); |
|
4598 |
vfs_unrefvfssw(vsw); |
|
4599 |
rootdev = rootvfs->vfs_dev; |
|
4600 |
||
4601 |
if (error) |
|
7439
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4602 |
cmn_err(CE_CONT, "Cannot mount root on %s fstype %s\n", |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4603 |
rootfs.bo_name, fstyp); |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4604 |
else |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4605 |
cmn_err(CE_CONT, "?root on %s fstype %s\n", |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4606 |
rootfs.bo_name, fstyp); |
0 | 4607 |
return (error); |
4608 |
} |
|
4609 |
||
4610 |
/* |
|
4611 |
* XXX this is called by nfs only and should probably be removed |
|
4612 |
* If booted with ASKNAME, prompt on the console for a filesystem |
|
4613 |
* name and return it. |
|
4614 |
*/ |
|
4615 |
void |
|
4616 |
getfsname(char *askfor, char *name, size_t namelen) |
|
4617 |
{ |
|
4618 |
if (boothowto & RB_ASKNAME) { |
|
4619 |
printf("%s name: ", askfor); |
|
4620 |
console_gets(name, namelen); |
|
4621 |
} |
|
4622 |
} |
|
4623 |
||
4624 |
/* |
|
7439
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4625 |
* Init the root filesystem type (rootfs.bo_fstype) from the "fstype" |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4626 |
* property. |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4627 |
* |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4628 |
* Filesystem types starting with the prefix "nfs" are diskless clients; |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4629 |
* init the root filename name (rootfs.bo_name), too. |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4630 |
* |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4631 |
* If we are booting via NFS we currently have these options: |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4632 |
* nfs - dynamically choose NFS V2, V3, or V4 (default) |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4633 |
* nfs2 - force NFS V2 |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4634 |
* nfs3 - force NFS V3 |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4635 |
* nfs4 - force NFS V4 |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4636 |
* Because we need to maintain backward compatibility with the naming |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4637 |
* convention that the NFS V2 filesystem name is "nfs" (see vfs_conf.c) |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4638 |
* we need to map "nfs" => "nfsdyn" and "nfs2" => "nfs". The dynamic |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4639 |
* nfs module will map the type back to either "nfs", "nfs3", or "nfs4". |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4640 |
* This is only for root filesystems, all other uses such as cachefs |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4641 |
* will expect that "nfs" == NFS V2. |
0 | 4642 |
*/ |
5084 | 4643 |
static void |
4644 |
getrootfs(char **fstypp, char **fsmodp) |
|
0 | 4645 |
{ |
4646 |
extern char *strplumb_get_netdev_path(void); |
|
4647 |
char *propstr = NULL; |
|
4648 |
||
7439
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4649 |
/* |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4650 |
* Check fstype property; for diskless it should be one of "nfs", |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4651 |
* "nfs2", "nfs3" or "nfs4". |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4652 |
*/ |
0 | 4653 |
if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), |
4654 |
DDI_PROP_DONTPASS, "fstype", &propstr) |
|
4655 |
== DDI_SUCCESS) { |
|
4656 |
(void) strncpy(rootfs.bo_fstype, propstr, BO_MAXFSNAME); |
|
4657 |
ddi_prop_free(propstr); |
|
3912 | 4658 |
|
4659 |
/* |
|
4660 |
* if the boot property 'fstype' is not set, but 'zfs-bootfs' is set, |
|
4661 |
* assume the type of this root filesystem is 'zfs'. |
|
4662 |
*/ |
|
4663 |
} else if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), |
|
4664 |
DDI_PROP_DONTPASS, "zfs-bootfs", &propstr) |
|
4665 |
== DDI_SUCCESS) { |
|
4666 |
(void) strncpy(rootfs.bo_fstype, "zfs", BO_MAXFSNAME); |
|
4667 |
ddi_prop_free(propstr); |
|
0 | 4668 |
} |
4669 |
||
5084 | 4670 |
if (strncmp(rootfs.bo_fstype, "nfs", 3) != 0) { |
4671 |
*fstypp = *fsmodp = rootfs.bo_fstype; |
|
4672 |
return; |
|
4673 |
} |
|
0 | 4674 |
|
4675 |
++netboot; |
|
7439
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4676 |
|
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4677 |
if (strcmp(rootfs.bo_fstype, "nfs2") == 0) |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4678 |
(void) strcpy(rootfs.bo_fstype, "nfs"); |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4679 |
else if (strcmp(rootfs.bo_fstype, "nfs") == 0) |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4680 |
(void) strcpy(rootfs.bo_fstype, "nfsdyn"); |
fb3bf1897b9d
6317111 newboot x86 diskless client refuses to use nfs vers3 for root filesystem
Pavel Filipensky <Pavel.Filipensky@Sun.COM>
parents:
6855
diff
changeset
|
4681 |
|
5084 | 4682 |
/* |
4683 |
* check if path to network interface is specified in bootpath |
|
4684 |
* or by a hypervisor domain configuration file. |
|
4685 |
* XXPV - enable strlumb_get_netdev_path() |
|
4686 |
*/ |
|
4687 |
if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_DONTPASS, |
|
4688 |
"xpv-nfsroot")) { |
|
4689 |
(void) strcpy(rootfs.bo_name, "/xpvd/xnf@0"); |
|
4690 |
} else if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), |
|
0 | 4691 |
DDI_PROP_DONTPASS, "bootpath", &propstr) |
4692 |
== DDI_SUCCESS) { |
|
4693 |
(void) strncpy(rootfs.bo_name, propstr, BO_MAXOBJNAME); |
|
4694 |
ddi_prop_free(propstr); |
|
4695 |
} else { |
|
4696 |
/* attempt to determine netdev_path via boot_mac address */ |
|
4697 |
netdev_path = strplumb_get_netdev_path(); |
|
4698 |
if (netdev_path == NULL) |
|
3446 | 4699 |
panic("cannot find boot network interface"); |
0 | 4700 |
(void) strncpy(rootfs.bo_name, netdev_path, BO_MAXOBJNAME); |
4701 |
} |
|
5084 | 4702 |
*fstypp = rootfs.bo_fstype; |
4703 |
*fsmodp = "nfs"; |
|
0 | 4704 |
} |
4705 |
#endif |
|
5331 | 4706 |
|
4707 |
/* |
|
4708 |
* VFS feature routines |
|
4709 |
*/ |
|
4710 |
||
4711 |
#define VFTINDEX(feature) (((feature) >> 32) & 0xFFFFFFFF) |
|
4712 |
#define VFTBITS(feature) ((feature) & 0xFFFFFFFFLL) |
|
4713 |
||
4714 |
/* Register a feature in the vfs */ |
|
4715 |
void |
|
4716 |
vfs_set_feature(vfs_t *vfsp, vfs_feature_t feature) |
|
4717 |
{ |
|
4718 |
/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */ |
|
4719 |
if (vfsp->vfs_implp == NULL) |
|
4720 |
return; |
|
4721 |
||
4722 |
vfsp->vfs_featureset[VFTINDEX(feature)] |= VFTBITS(feature); |
|
4723 |
} |
|
4724 |
||
13178
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4725 |
void |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4726 |
vfs_clear_feature(vfs_t *vfsp, vfs_feature_t feature) |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4727 |
{ |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4728 |
/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */ |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4729 |
if (vfsp->vfs_implp == NULL) |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4730 |
return; |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4731 |
vfsp->vfs_featureset[VFTINDEX(feature)] &= VFTBITS(~feature); |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4732 |
} |
5f70b43d6386
6977619 NULL pointer deference in sa_handle_get_from_db()
Mark Shellenbaum <Mark.Shellenbaum@Oracle.COM>
parents:
13108
diff
changeset
|
4733 |
|
5331 | 4734 |
/* |
4735 |
* Query a vfs for a feature. |
|
4736 |
* Returns 1 if feature is present, 0 if not |
|
4737 |
*/ |
|
4738 |
int |
|
4739 |
vfs_has_feature(vfs_t *vfsp, vfs_feature_t feature) |
|
4740 |
{ |
|
4741 |
int ret = 0; |
|
4742 |
||
4743 |
/* Note that vfs_featureset[] is found in *vfsp->vfs_implp */ |
|
4744 |
if (vfsp->vfs_implp == NULL) |
|
4745 |
return (ret); |
|
4746 |
||
4747 |
if (vfsp->vfs_featureset[VFTINDEX(feature)] & VFTBITS(feature)) |
|
4748 |
ret = 1; |
|
4749 |
||
4750 |
return (ret); |
|
4751 |
} |
|
6224
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4752 |
|
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4753 |
/* |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4754 |
* Propagate feature set from one vfs to another |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4755 |
*/ |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4756 |
void |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4757 |
vfs_propagate_features(vfs_t *from, vfs_t *to) |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4758 |
{ |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4759 |
int i; |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4760 |
|
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4761 |
if (to->vfs_implp == NULL || from->vfs_implp == NULL) |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4762 |
return; |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4763 |
|
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4764 |
for (i = 1; i <= to->vfs_featureset[0]; i++) { |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4765 |
to->vfs_featureset[i] = from->vfs_featureset[i]; |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4766 |
} |
723c47040516
6671591 lofs needs to propagate vfs features from real vfs
marks
parents:
5331
diff
changeset
|
4767 |
} |
6734 | 4768 |
|
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4769 |
#define LOFINODE_PATH "/dev/lofi/%d" |
6734 | 4770 |
|
4771 |
/* |
|
4772 |
* Return the vnode for the lofi node if there's a lofi mount in place. |
|
4773 |
* Returns -1 when there's no lofi node, 0 on success, and > 0 on |
|
4774 |
* failure. |
|
4775 |
*/ |
|
4776 |
int |
|
4777 |
vfs_get_lofi(vfs_t *vfsp, vnode_t **vpp) |
|
4778 |
{ |
|
4779 |
char *path = NULL; |
|
4780 |
int strsize; |
|
4781 |
int err; |
|
4782 |
||
4783 |
if (vfsp->vfs_lofi_minor == 0) { |
|
4784 |
*vpp = NULL; |
|
4785 |
return (-1); |
|
4786 |
} |
|
4787 |
||
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4788 |
strsize = snprintf(NULL, 0, LOFINODE_PATH, vfsp->vfs_lofi_minor); |
6734 | 4789 |
path = kmem_alloc(strsize + 1, KM_SLEEP); |
12633
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4790 |
(void) snprintf(path, strsize + 1, LOFINODE_PATH, vfsp->vfs_lofi_minor); |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4791 |
|
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4792 |
/* |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4793 |
* We may be inside a zone, so we need to use the /dev path, but |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4794 |
* it's created asynchronously, so we wait here. |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4795 |
*/ |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4796 |
for (;;) { |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4797 |
err = lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, vpp); |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4798 |
|
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4799 |
if (err != ENOENT) |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4800 |
break; |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4801 |
|
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4802 |
if ((err = delay_sig(hz / 8)) == EINTR) |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4803 |
break; |
9f2cda0ed938
PSARC 2010/144 lofi(7D) in non global zones
John Levon <john.levon@sun.com>
parents:
11173
diff
changeset
|
4804 |
} |
6734 | 4805 |
|
4806 |
if (err) |
|
4807 |
*vpp = NULL; |
|
4808 |
||
4809 |
kmem_free(path, strsize + 1); |
|
4810 |
return (err); |
|
4811 |
} |