3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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 /*
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2011, Joyent, Inc. All rights reserved.
24 */
25
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/sysmacros.h>
29 #include <sys/kmem.h>
30 #include <sys/time.h>
31 #include <sys/pathname.h>
32 #include <sys/vfs.h>
33 #include <sys/vfs_opreg.h>
34 #include <sys/vnode.h>
35 #include <sys/stat.h>
36 #include <sys/uio.h>
37 #include <sys/stat.h>
38 #include <sys/errno.h>
39 #include <sys/cmn_err.h>
40 #include <sys/cred.h>
41 #include <sys/statvfs.h>
42 #include <sys/mount.h>
43 #include <sys/debug.h>
74 static mntopts_t tmpfs_proto_opttbl;
75
76 static vfsdef_t vfw = {
77 VFSDEF_VERSION,
78 "tmpfs",
79 tmpfsinit,
80 VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_ZMOUNT,
81 &tmpfs_proto_opttbl
82 };
83
84 /*
85 * in-kernel mnttab options
86 */
87 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL };
88 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL };
89
90 static mntopt_t tmpfs_options[] = {
91 /* Option name Cancel Opt Arg Flags Data */
92 { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, NULL},
93 { MNTOPT_NOXATTR, noxattr_cancel, NULL, NULL, NULL},
94 { "size", NULL, "0", MO_HASVALUE, NULL}
95 };
96
97
98 static mntopts_t tmpfs_proto_opttbl = {
99 sizeof (tmpfs_options) / sizeof (mntopt_t),
100 tmpfs_options
101 };
102
103 /*
104 * Module linkage information
105 */
106 static struct modlfs modlfs = {
107 &mod_fsops, "filesystem for tmpfs", &vfw
108 };
109
110 static struct modlinkage modlinkage = {
111 MODREV_1, &modlfs, NULL
112 };
113
114 int
210 */
211 tmpfs_minfree = btopr(TMPMINFREE);
212 }
213
214 /*
215 * The maximum amount of space tmpfs can allocate is
216 * TMPMAXPROCKMEM percent of kernel memory
217 */
218 if (tmpfs_maxkmem == 0)
219 tmpfs_maxkmem = MAX(PAGESIZE, kmem_maxavail() / TMPMAXFRACKMEM);
220
221 if ((tmpfs_major = getudev()) == (major_t)-1) {
222 cmn_err(CE_WARN, "tmpfsinit: Can't get unique device number.");
223 tmpfs_major = 0;
224 }
225 mutex_init(&tmpfs_minor_lock, NULL, MUTEX_DEFAULT, NULL);
226 return (0);
227 }
228
229 static int
230 tmp_mount(
231 struct vfs *vfsp,
232 struct vnode *mvp,
233 struct mounta *uap,
234 struct cred *cr)
235 {
236 struct tmount *tm = NULL;
237 struct tmpnode *tp;
238 struct pathname dpn;
239 int error;
240 pgcnt_t anonmax;
241 struct vattr rattr;
242 int got_attrs;
243
244 char *sizestr;
245
246 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
247 return (error);
248
249 if (mvp->v_type != VDIR)
250 return (ENOTDIR);
251
252 mutex_enter(&mvp->v_lock);
253 if ((uap->flags & MS_REMOUNT) == 0 && (uap->flags & MS_OVERLAY) == 0 &&
254 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
255 mutex_exit(&mvp->v_lock);
256 return (EBUSY);
257 }
258 mutex_exit(&mvp->v_lock);
259
260 /*
261 * Having the resource be anything but "swap" doesn't make sense.
262 */
263 vfs_setresource(vfsp, "swap", 0);
264
265 /*
266 * now look for options we understand...
267 */
268
269 /* tmpfs doesn't support read-only mounts */
270 if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) {
271 error = EINVAL;
272 goto out;
273 }
274
275 /*
276 * tm_anonmax is set according to the mount arguments
277 * if any. Otherwise, it is set to a maximum value.
278 */
279 if (vfs_optionisset(vfsp, "size", &sizestr)) {
280 if ((error = tmp_convnum(sizestr, &anonmax)) != 0)
281 goto out;
282 } else {
283 anonmax = ULONG_MAX;
284 }
285
286 if (error = pn_get(uap->dir,
287 (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn))
288 goto out;
289
290 if (uap->flags & MS_REMOUNT) {
291 tm = (struct tmount *)VFSTOTM(vfsp);
292
293 /*
294 * If we change the size so its less than what is currently
295 * being used, we allow that. The file system will simply be
296 * full until enough files have been removed to get below the
297 * new max.
298 */
299 mutex_enter(&tm->tm_contents);
300 tm->tm_anonmax = anonmax;
301 mutex_exit(&tm->tm_contents);
302 goto out;
303 }
304
305 if ((tm = tmp_memalloc(sizeof (struct tmount), 0)) == NULL) {
324 */
325 mutex_init(&tm->tm_contents, NULL, MUTEX_DEFAULT, NULL);
326 mutex_init(&tm->tm_renamelck, NULL, MUTEX_DEFAULT, NULL);
327
328 tm->tm_vfsp = vfsp;
329 tm->tm_anonmax = anonmax;
330
331 vfsp->vfs_data = (caddr_t)tm;
332 vfsp->vfs_fstype = tmpfsfstype;
333 vfsp->vfs_dev = tm->tm_dev;
334 vfsp->vfs_bsize = PAGESIZE;
335 vfsp->vfs_flag |= VFS_NOTRUNC;
336 vfs_make_fsid(&vfsp->vfs_fsid, tm->tm_dev, tmpfsfstype);
337 tm->tm_mntpath = tmp_memalloc(dpn.pn_pathlen + 1, TMP_MUSTHAVE);
338 (void) strcpy(tm->tm_mntpath, dpn.pn_path);
339
340 /*
341 * allocate and initialize root tmpnode structure
342 */
343 bzero(&rattr, sizeof (struct vattr));
344 rattr.va_mode = (mode_t)(S_IFDIR | 0777); /* XXX modes */
345 rattr.va_type = VDIR;
346 rattr.va_rdev = 0;
347 tp = tmp_memalloc(sizeof (struct tmpnode), TMP_MUSTHAVE);
348 tmpnode_init(tm, tp, &rattr, cr);
349
350 /*
351 * Get the mode, uid, and gid from the underlying mount point.
352 */
353 rattr.va_mask = AT_MODE|AT_UID|AT_GID; /* Hint to getattr */
354 got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr, NULL);
355
356 rw_enter(&tp->tn_rwlock, RW_WRITER);
357 TNTOV(tp)->v_flag |= VROOT;
358
359 /*
360 * If the getattr succeeded, use its results. Otherwise allow
361 * the previously set hardwired defaults to prevail.
362 */
363 if (got_attrs == 0) {
364 tp->tn_mode = rattr.va_mode;
365 tp->tn_uid = rattr.va_uid;
366 tp->tn_gid = rattr.va_gid;
367 }
368
369 /*
370 * initialize linked list of tmpnodes so that the back pointer of
371 * the root tmpnode always points to the last one on the list
372 * and the forward pointer of the last node is null
373 */
374 tp->tn_back = tp;
375 tp->tn_forw = NULL;
376 tp->tn_nlink = 0;
377 tm->tm_rootnode = tp;
378
379 tdirinit(tp, tp);
380
381 rw_exit(&tp->tn_rwlock);
382
383 pn_free(&dpn);
384 error = 0;
|
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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 /*
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Joyent, Inc.
24 */
25
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/sysmacros.h>
29 #include <sys/kmem.h>
30 #include <sys/time.h>
31 #include <sys/pathname.h>
32 #include <sys/vfs.h>
33 #include <sys/vfs_opreg.h>
34 #include <sys/vnode.h>
35 #include <sys/stat.h>
36 #include <sys/uio.h>
37 #include <sys/stat.h>
38 #include <sys/errno.h>
39 #include <sys/cmn_err.h>
40 #include <sys/cred.h>
41 #include <sys/statvfs.h>
42 #include <sys/mount.h>
43 #include <sys/debug.h>
74 static mntopts_t tmpfs_proto_opttbl;
75
76 static vfsdef_t vfw = {
77 VFSDEF_VERSION,
78 "tmpfs",
79 tmpfsinit,
80 VSW_HASPROTO|VSW_CANREMOUNT|VSW_STATS|VSW_ZMOUNT,
81 &tmpfs_proto_opttbl
82 };
83
84 /*
85 * in-kernel mnttab options
86 */
87 static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL };
88 static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL };
89
90 static mntopt_t tmpfs_options[] = {
91 /* Option name Cancel Opt Arg Flags Data */
92 { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, NULL},
93 { MNTOPT_NOXATTR, noxattr_cancel, NULL, NULL, NULL},
94 { "size", NULL, "0", MO_HASVALUE, NULL},
95 { "mode", NULL, NULL, MO_HASVALUE, NULL}
96 };
97
98
99 static mntopts_t tmpfs_proto_opttbl = {
100 sizeof (tmpfs_options) / sizeof (mntopt_t),
101 tmpfs_options
102 };
103
104 /*
105 * Module linkage information
106 */
107 static struct modlfs modlfs = {
108 &mod_fsops, "filesystem for tmpfs", &vfw
109 };
110
111 static struct modlinkage modlinkage = {
112 MODREV_1, &modlfs, NULL
113 };
114
115 int
211 */
212 tmpfs_minfree = btopr(TMPMINFREE);
213 }
214
215 /*
216 * The maximum amount of space tmpfs can allocate is
217 * TMPMAXPROCKMEM percent of kernel memory
218 */
219 if (tmpfs_maxkmem == 0)
220 tmpfs_maxkmem = MAX(PAGESIZE, kmem_maxavail() / TMPMAXFRACKMEM);
221
222 if ((tmpfs_major = getudev()) == (major_t)-1) {
223 cmn_err(CE_WARN, "tmpfsinit: Can't get unique device number.");
224 tmpfs_major = 0;
225 }
226 mutex_init(&tmpfs_minor_lock, NULL, MUTEX_DEFAULT, NULL);
227 return (0);
228 }
229
230 static int
231 tmp_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
232 {
233 struct tmount *tm = NULL;
234 struct tmpnode *tp;
235 struct pathname dpn;
236 int error;
237 pgcnt_t anonmax;
238 struct vattr rattr;
239 int got_attrs;
240 boolean_t mode_arg = B_FALSE;
241 mode_t root_mode = 0777;
242 char *argstr;
243
244 if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
245 return (error);
246
247 if (mvp->v_type != VDIR)
248 return (ENOTDIR);
249
250 mutex_enter(&mvp->v_lock);
251 if ((uap->flags & MS_REMOUNT) == 0 && (uap->flags & MS_OVERLAY) == 0 &&
252 (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
253 mutex_exit(&mvp->v_lock);
254 return (EBUSY);
255 }
256 mutex_exit(&mvp->v_lock);
257
258 /*
259 * Having the resource be anything but "swap" doesn't make sense.
260 */
261 vfs_setresource(vfsp, "swap", 0);
262
263 /*
264 * now look for options we understand...
265 */
266
267 /* tmpfs doesn't support read-only mounts */
268 if (vfs_optionisset(vfsp, MNTOPT_RO, NULL)) {
269 error = EINVAL;
270 goto out;
271 }
272
273 /*
274 * tm_anonmax is set according to the mount arguments
275 * if any. Otherwise, it is set to a maximum value.
276 */
277 if (vfs_optionisset(vfsp, "size", &argstr)) {
278 if ((error = tmp_convnum(argstr, &anonmax)) != 0)
279 goto out;
280 } else {
281 anonmax = ULONG_MAX;
282 }
283
284 /*
285 * The "mode" mount argument allows the operator to override the
286 * permissions of the root of the tmpfs mount.
287 */
288 if (vfs_optionisset(vfsp, "mode", &argstr)) {
289 if ((error = tmp_convmode(argstr, &root_mode)) != 0) {
290 goto out;
291 }
292 mode_arg = B_TRUE;
293 }
294
295 if (error = pn_get(uap->dir,
296 (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn))
297 goto out;
298
299 if (uap->flags & MS_REMOUNT) {
300 tm = (struct tmount *)VFSTOTM(vfsp);
301
302 /*
303 * If we change the size so its less than what is currently
304 * being used, we allow that. The file system will simply be
305 * full until enough files have been removed to get below the
306 * new max.
307 */
308 mutex_enter(&tm->tm_contents);
309 tm->tm_anonmax = anonmax;
310 mutex_exit(&tm->tm_contents);
311 goto out;
312 }
313
314 if ((tm = tmp_memalloc(sizeof (struct tmount), 0)) == NULL) {
333 */
334 mutex_init(&tm->tm_contents, NULL, MUTEX_DEFAULT, NULL);
335 mutex_init(&tm->tm_renamelck, NULL, MUTEX_DEFAULT, NULL);
336
337 tm->tm_vfsp = vfsp;
338 tm->tm_anonmax = anonmax;
339
340 vfsp->vfs_data = (caddr_t)tm;
341 vfsp->vfs_fstype = tmpfsfstype;
342 vfsp->vfs_dev = tm->tm_dev;
343 vfsp->vfs_bsize = PAGESIZE;
344 vfsp->vfs_flag |= VFS_NOTRUNC;
345 vfs_make_fsid(&vfsp->vfs_fsid, tm->tm_dev, tmpfsfstype);
346 tm->tm_mntpath = tmp_memalloc(dpn.pn_pathlen + 1, TMP_MUSTHAVE);
347 (void) strcpy(tm->tm_mntpath, dpn.pn_path);
348
349 /*
350 * allocate and initialize root tmpnode structure
351 */
352 bzero(&rattr, sizeof (struct vattr));
353 rattr.va_mode = (mode_t)(S_IFDIR | root_mode);
354 rattr.va_type = VDIR;
355 rattr.va_rdev = 0;
356 tp = tmp_memalloc(sizeof (struct tmpnode), TMP_MUSTHAVE);
357 tmpnode_init(tm, tp, &rattr, cr);
358
359 /*
360 * Get the mode, uid, and gid from the underlying mount point.
361 */
362 rattr.va_mask = AT_MODE|AT_UID|AT_GID; /* Hint to getattr */
363 got_attrs = VOP_GETATTR(mvp, &rattr, 0, cr, NULL);
364
365 rw_enter(&tp->tn_rwlock, RW_WRITER);
366 TNTOV(tp)->v_flag |= VROOT;
367
368 /*
369 * If the getattr succeeded, use its results. Otherwise allow
370 * the previously set hardwired defaults to prevail.
371 */
372 if (got_attrs == 0) {
373 if (!mode_arg) {
374 /*
375 * Only use the underlying mount point for the
376 * mode if the "mode" mount argument was not
377 * provided.
378 */
379 tp->tn_mode = rattr.va_mode;
380 }
381 tp->tn_uid = rattr.va_uid;
382 tp->tn_gid = rattr.va_gid;
383 }
384
385 /*
386 * initialize linked list of tmpnodes so that the back pointer of
387 * the root tmpnode always points to the last one on the list
388 * and the forward pointer of the last node is null
389 */
390 tp->tn_back = tp;
391 tp->tn_forw = NULL;
392 tp->tn_nlink = 0;
393 tm->tm_rootnode = tp;
394
395 tdirinit(tp, tp);
396
397 rw_exit(&tp->tn_rwlock);
398
399 pn_free(&dpn);
400 error = 0;
|