From 401bc9af09d3e2bcb61df16867750651ccb30004 Mon Sep 17 00:00:00 2001 From: "Joshua M. Clulow" Date: Tue, 27 Sep 2016 11:38:30 -0700 Subject: 7752 tmpfs should support gigabyte sizes 7753 tmpfs should support "mode" option Reviewed by: Robert Mustacchi Reviewed by: Patrick Mooney Reviewed by: Hans Rosenfeld Reviewed by: Garrett D'Amore Approved by: Dan McDonald --- usr/src/uts/common/fs/tmpfs/tmp_subr.c | 127 ++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 41 deletions(-) (limited to 'usr/src/uts/common/fs/tmpfs/tmp_subr.c') 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 @@ -40,9 +41,17 @@ #include #include #include +#include +#include + +#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); +} -- cgit v1.2.3