summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua M. Clulow <jmc@joyent.com>2016-09-27 11:38:30 -0700
committerRobert Mustacchi <rm@joyent.com>2017-03-23 01:01:14 +0000
commit401bc9af09d3e2bcb61df16867750651ccb30004 (patch)
treed637032fdb75429a173b0238fb867f688494749c
parent7909625fdb7ecb20e9b7a777cfc0ec7ee63b4642 (diff)
downloadillumos-gate-401bc9af09d3e2bcb61df16867750651ccb30004.tar.gz
7752 tmpfs should support gigabyte sizes
7753 tmpfs should support "mode" option Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Dan McDonald <danmcd@omniti.com>
-rw-r--r--usr/src/man/man1m/mount_tmpfs.1m24
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_subr.c127
-rw-r--r--usr/src/uts/common/fs/tmpfs/tmp_vfsops.c42
-rw-r--r--usr/src/uts/common/sys/fs/tmp.h6
4 files changed, 139 insertions, 60 deletions
diff --git a/usr/src/man/man1m/mount_tmpfs.1m b/usr/src/man/man1m/mount_tmpfs.1m
index ef7a2a6a35..f01fa049b6 100644
--- a/usr/src/man/man1m/mount_tmpfs.1m
+++ b/usr/src/man/man1m/mount_tmpfs.1m
@@ -1,10 +1,10 @@
'\" te
.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved
-.\" Copyright (c) 2011, Joyent, Inc. All Rights Reserved
+.\" Copyright 2015 Joyent, Inc.
.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License.
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License.
.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH MOUNT_TMPFS 1M "Dec 2, 2011"
+.TH MOUNT_TMPFS 1M "Mar 12, 2015"
.SH NAME
mount_tmpfs \- mount tmpfs file systems
.SH SYNOPSIS
@@ -26,7 +26,8 @@ remain hidden until the file system is once again unmounted. The attributes
(mode, owner, and group) of the root of the \fBtmpfs\fR filesystem are
inherited from the underlying \fImount_point\fR, provided that those attributes
are determinable. If not, the root's attributes are set to their default
-values.
+values. The mode may also be overriden by the \fBmode\fR mount option, which
+takes precedence if set.
.sp
.LP
The \fIspecial\fR argument is usually specified as \fBswap\fR but is in fact
@@ -55,13 +56,28 @@ set with \fBremount\fR reverts to no limit.
.sp
.ne 2
.na
+\fBmode=\fIoctalmode\fR\fR
+.ad
+.RS 19n
+The \fImode\fR argument controls the permissions of the \fBtmpfs\fR mount
+point. The argument must be an octal number, of the form passed to
+\fBchmod\fR(1). Only the access mode, setuid, setgid, and sticky bits (a mask
+of \fB07777\fR) may be set. If this option is not provided then the default
+mode behaviour, as described above, applies.
+.RE
+
+.sp
+.sp
+.ne 2
+.na
\fBsize=\fIsz\fR\fR
.ad
.RS 19n
The \fIsz\fR argument controls the size of this particular \fBtmpfs\fR file
system. If the argument is has a `k' suffix, the number will be interpreted as
a number of kilobytes. An `m' suffix will be interpreted as a number of
-megabytes. No suffix is interpreted as bytes. In all cases, the actual size of
+megabytes. A `g' suffix will be interpreted as a number of gigabytes.
+No suffix is interpreted as bytes. In all cases, the actual size of
the file system is the number of bytes specified, rounded up to the physical
pagesize of the system.
.RE
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_subr.c b/usr/src/uts/common/fs/tmpfs/tmp_subr.c
index 2e59d28d80..0a3c07b381 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_subr.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_subr.c
@@ -20,6 +20,7 @@
*/
/*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
#include <sys/types.h>
@@ -40,9 +41,17 @@
#include <sys/policy.h>
#include <sys/fs/tmp.h>
#include <sys/fs/tmpnode.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+
+#define KILOBYTE 1024
+#define MEGABYTE (1024 * KILOBYTE)
+#define GIGABYTE (1024 * MEGABYTE)
#define MODESHIFT 3
+#define VALIDMODEBITS 07777
+
int
tmp_taccess(void *vtp, int mode, struct cred *cred)
{
@@ -71,7 +80,6 @@ tmp_taccess(void *vtp, int mode, struct cred *cred)
* a plain file and you have write access to that file.
* Function returns 0 if remove access is granted.
*/
-
int
tmp_sticky_remove_access(struct tmpnode *dir, struct tmpnode *entry,
struct cred *cr)
@@ -128,70 +136,81 @@ tmp_memfree(void *cp, size_t size)
* maximum value encoded in 'str' is PAGESIZE * ULONG_MAX, while the value
* returned in 'maxpg' is at most ULONG_MAX.
*
- * If the number is followed by a "k" or "K", the value is converted from
- * kilobytes to bytes. If it is followed by an "m" or "M" it is converted
- * from megabytes to bytes. If it is not followed by a character it is
- * assumed to be in bytes. Multiple letter options are allowed, so for instance
- * '2mk' is interpreted as 2gb.
+ * The number may be followed by a magnitude suffix: "k" or "K" for kilobytes;
+ * "m" or "M" for megabytes; "g" or "G" for gigabytes. This interface allows
+ * for an arguably esoteric interpretation of multiple suffix characters:
+ * namely, they cascade. For example, the caller may specify "2mk", which is
+ * interpreted as 2 gigabytes. It would seem, at this late stage, that the
+ * horse has left not only the barn but indeed the country, and possibly the
+ * entire planetary system.
*
* Parse and overflow errors are detected and a non-zero number returned on
* error.
*/
-
int
tmp_convnum(char *str, pgcnt_t *maxpg)
{
- uint64_t num = 0, oldnum;
+ u_longlong_t num = 0;
#ifdef _LP64
- uint64_t max_bytes = ULONG_MAX;
+ u_longlong_t max_bytes = ULONG_MAX;
#else
- uint64_t max_bytes = PAGESIZE * (uint64_t)ULONG_MAX;
+ u_longlong_t max_bytes = PAGESIZE * (uint64_t)ULONG_MAX;
#endif
char *c;
-
- if (str == NULL)
+ const struct convchar {
+ char *cc_char;
+ uint64_t cc_factor;
+ } convchars[] = {
+ { "kK", KILOBYTE },
+ { "mM", MEGABYTE },
+ { "gG", GIGABYTE },
+ { NULL, 0 }
+ };
+
+ if (str == NULL) {
return (EINVAL);
+ }
c = str;
/*
- * Convert str to number
+ * Convert the initial numeric portion of the input string.
*/
- while ((*c >= '0') && (*c <= '9')) {
- oldnum = num;
- num = num * 10 + (*c++ - '0');
- if (oldnum > num) /* overflow */
- return (EINVAL);
+ if (ddi_strtoull(str, &c, 10, &num) != 0) {
+ return (EINVAL);
}
/*
- * Terminate on null
+ * Apply the (potentially cascading) magnitude suffixes until an
+ * invalid character is found, or the string comes to an end.
*/
- while (*c != '\0') {
- switch (*c++) {
+ for (; *c != '\0'; c++) {
+ int i;
+
+ for (i = 0; convchars[i].cc_char != NULL; i++) {
+ /*
+ * Check if this character matches this multiplier
+ * class:
+ */
+ if (strchr(convchars[i].cc_char, *c) != NULL) {
+ /*
+ * Check for overflow:
+ */
+ if (num > max_bytes / convchars[i].cc_factor) {
+ return (EINVAL);
+ }
+
+ num *= convchars[i].cc_factor;
+ goto valid_char;
+ }
+ }
/*
- * convert from kilobytes
+ * This was not a valid multiplier suffix character.
*/
- case 'k':
- case 'K':
- if (num > max_bytes / 1024) /* will overflow */
- return (EINVAL);
- num *= 1024;
- break;
+ return (EINVAL);
- /*
- * convert from megabytes
- */
- case 'm':
- case 'M':
- if (num > max_bytes / (1024 * 1024)) /* will overflow */
- return (EINVAL);
- num *= 1024 * 1024;
- break;
-
- default:
- return (EINVAL);
- }
+valid_char:
+ continue;
}
/*
@@ -204,3 +223,29 @@ tmp_convnum(char *str, pgcnt_t *maxpg)
return (EINVAL);
return (0);
}
+
+/*
+ * Parse an octal mode string for use as the permissions set for the root
+ * of the tmpfs mount.
+ */
+int
+tmp_convmode(char *str, mode_t *mode)
+{
+ ulong_t num;
+ char *c;
+
+ if (str == NULL) {
+ return (EINVAL);
+ }
+
+ if (ddi_strtoul(str, &c, 8, &num) != 0) {
+ return (EINVAL);
+ }
+
+ if ((num & ~VALIDMODEBITS) != 0) {
+ return (EINVAL);
+ }
+
+ *mode = VALIDMODEBITS & num;
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
index f22cc3ecf0..f0e0c54d3e 100644
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright 2015 Joyent, Inc.
*/
#include <sys/types.h>
@@ -91,7 +91,8 @@ static mntopt_t tmpfs_options[] = {
/* Option name Cancel Opt Arg Flags Data */
{ MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, NULL},
{ MNTOPT_NOXATTR, noxattr_cancel, NULL, NULL, NULL},
- { "size", NULL, "0", MO_HASVALUE, NULL}
+ { "size", NULL, "0", MO_HASVALUE, NULL},
+ { "mode", NULL, NULL, MO_HASVALUE, NULL}
};
@@ -227,11 +228,7 @@ tmpfsinit(int fstype, char *name)
}
static int
-tmp_mount(
- struct vfs *vfsp,
- struct vnode *mvp,
- struct mounta *uap,
- struct cred *cr)
+tmp_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
{
struct tmount *tm = NULL;
struct tmpnode *tp;
@@ -240,8 +237,9 @@ tmp_mount(
pgcnt_t anonmax;
struct vattr rattr;
int got_attrs;
-
- char *sizestr;
+ boolean_t mode_arg = B_FALSE;
+ mode_t root_mode = 0777;
+ char *argstr;
if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
return (error);
@@ -276,13 +274,24 @@ tmp_mount(
* tm_anonmax is set according to the mount arguments
* if any. Otherwise, it is set to a maximum value.
*/
- if (vfs_optionisset(vfsp, "size", &sizestr)) {
- if ((error = tmp_convnum(sizestr, &anonmax)) != 0)
+ if (vfs_optionisset(vfsp, "size", &argstr)) {
+ if ((error = tmp_convnum(argstr, &anonmax)) != 0)
goto out;
} else {
anonmax = ULONG_MAX;
}
+ /*
+ * The "mode" mount argument allows the operator to override the
+ * permissions of the root of the tmpfs mount.
+ */
+ if (vfs_optionisset(vfsp, "mode", &argstr)) {
+ if ((error = tmp_convmode(argstr, &root_mode)) != 0) {
+ goto out;
+ }
+ mode_arg = B_TRUE;
+ }
+
if (error = pn_get(uap->dir,
(uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn))
goto out;
@@ -341,7 +350,7 @@ tmp_mount(
* allocate and initialize root tmpnode structure
*/
bzero(&rattr, sizeof (struct vattr));
- rattr.va_mode = (mode_t)(S_IFDIR | 0777); /* XXX modes */
+ rattr.va_mode = (mode_t)(S_IFDIR | root_mode);
rattr.va_type = VDIR;
rattr.va_rdev = 0;
tp = tmp_memalloc(sizeof (struct tmpnode), TMP_MUSTHAVE);
@@ -361,7 +370,14 @@ tmp_mount(
* the previously set hardwired defaults to prevail.
*/
if (got_attrs == 0) {
- tp->tn_mode = rattr.va_mode;
+ if (!mode_arg) {
+ /*
+ * Only use the underlying mount point for the
+ * mode if the "mode" mount argument was not
+ * provided.
+ */
+ tp->tn_mode = rattr.va_mode;
+ }
tp->tn_uid = rattr.va_uid;
tp->tn_gid = rattr.va_gid;
}
diff --git a/usr/src/uts/common/sys/fs/tmp.h b/usr/src/uts/common/sys/fs/tmp.h
index 68dd67c61e..fb07de6588 100644
--- a/usr/src/uts/common/sys/fs/tmp.h
+++ b/usr/src/uts/common/sys/fs/tmp.h
@@ -22,12 +22,13 @@
* Copyright 2007 Sun Microsystems, Inc.
* All rights reserved. Use is subject to license terms.
*/
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
#ifndef _SYS_FS_TMP_H
#define _SYS_FS_TMP_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -108,6 +109,7 @@ extern int tmp_taccess(void *, int, struct cred *);
extern int tmp_sticky_remove_access(struct tmpnode *, struct tmpnode *,
struct cred *);
extern int tmp_convnum(char *, pgcnt_t *);
+extern int tmp_convmode(char *, mode_t *);
extern int tdirenter(struct tmount *, struct tmpnode *, char *,
enum de_op, struct tmpnode *, struct tmpnode *, struct vattr *,
struct tmpnode **, struct cred *, caller_context_t *);