From: Miklos Szeredi <[email protected]>
Add .show_options super operation to tmpfs.
Signed-off-by: Miklos Szeredi <[email protected]>
---
Index: linux/mm/shmem.c
===================================================================
--- linux.orig/mm/shmem.c 2008-01-21 21:20:04.000000000 +0100
+++ linux/mm/shmem.c 2008-01-21 21:30:04.000000000 +0100
@@ -49,6 +49,7 @@
#include <linux/ctype.h>
#include <linux/migrate.h>
#include <linux/highmem.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
@@ -198,7 +199,7 @@ static DEFINE_MUTEX(shmem_swaplist_mutex
static void shmem_free_blocks(struct inode *inode, long pages)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
- if (sbinfo->max_blocks) {
+ if (sbinfo->config.max_blocks) {
spin_lock(&sbinfo->stat_lock);
sbinfo->free_blocks += pages;
inode->i_blocks -= pages*BLOCKS_PER_PAGE;
@@ -209,7 +210,7 @@ static void shmem_free_blocks(struct ino
static int shmem_reserve_inode(struct super_block *sb)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- if (sbinfo->max_inodes) {
+ if (sbinfo->config.max_inodes) {
spin_lock(&sbinfo->stat_lock);
if (!sbinfo->free_inodes) {
spin_unlock(&sbinfo->stat_lock);
@@ -224,7 +225,7 @@ static int shmem_reserve_inode(struct su
static void shmem_free_inode(struct super_block *sb)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- if (sbinfo->max_inodes) {
+ if (sbinfo->config.max_inodes) {
spin_lock(&sbinfo->stat_lock);
sbinfo->free_inodes++;
spin_unlock(&sbinfo->stat_lock);
@@ -388,7 +389,7 @@ static swp_entry_t *shmem_swp_alloc(stru
* page (and perhaps indirect index pages) yet to allocate:
* a waste to allocate index if we cannot allocate data.
*/
- if (sbinfo->max_blocks) {
+ if (sbinfo->config.max_blocks) {
spin_lock(&sbinfo->stat_lock);
if (sbinfo->free_blocks <= 1) {
spin_unlock(&sbinfo->stat_lock);
@@ -1338,7 +1339,7 @@ repeat:
} else {
shmem_swp_unmap(entry);
sbinfo = SHMEM_SB(inode->i_sb);
- if (sbinfo->max_blocks) {
+ if (sbinfo->config.max_blocks) {
spin_lock(&sbinfo->stat_lock);
if (sbinfo->free_blocks == 0 ||
shmem_acct_block(info->flags)) {
@@ -1519,8 +1520,9 @@ shmem_get_inode(struct super_block *sb,
case S_IFREG:
inode->i_op = &shmem_inode_operations;
inode->i_fop = &shmem_file_operations;
- mpol_shared_policy_init(&info->policy, sbinfo->policy,
- &sbinfo->policy_nodes);
+ mpol_shared_policy_init(&info->policy,
+ sbinfo->config.policy,
+ &sbinfo->config.policy_nodes);
break;
case S_IFDIR:
inc_nlink(inode);
@@ -1720,12 +1722,12 @@ static int shmem_statfs(struct dentry *d
buf->f_bsize = PAGE_CACHE_SIZE;
buf->f_namelen = NAME_MAX;
spin_lock(&sbinfo->stat_lock);
- if (sbinfo->max_blocks) {
- buf->f_blocks = sbinfo->max_blocks;
+ if (sbinfo->config.max_blocks) {
+ buf->f_blocks = sbinfo->config.max_blocks;
buf->f_bavail = buf->f_bfree = sbinfo->free_blocks;
}
- if (sbinfo->max_inodes) {
- buf->f_files = sbinfo->max_inodes;
+ if (sbinfo->config.max_inodes) {
+ buf->f_files = sbinfo->config.max_inodes;
buf->f_ffree = sbinfo->free_inodes;
}
/* else leave those fields 0 like simple_statfs */
@@ -2077,9 +2079,8 @@ static const struct export_operations sh
.fh_to_dentry = shmem_fh_to_dentry,
};
-static int shmem_parse_options(char *options, int *mode, uid_t *uid,
- gid_t *gid, unsigned long *blocks, unsigned long *inodes,
- int *policy, nodemask_t *policy_nodes)
+static int shmem_parse_options(char *options, struct shmem_config *config,
+ bool remount)
{
char *this_char, *value, *rest;
@@ -2122,35 +2123,43 @@ static int shmem_parse_options(char *opt
}
if (*rest)
goto bad_val;
- *blocks = DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
+ config->max_blocks =
+ DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
+ config->max_blocks_changed = 1;
} else if (!strcmp(this_char,"nr_blocks")) {
- *blocks = memparse(value,&rest);
+ config->max_blocks = memparse(value, &rest);
+ config->max_blocks_changed = 1;
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"nr_inodes")) {
- *inodes = memparse(value,&rest);
+ config->max_inodes = memparse(value, &rest);
+ config->max_inodes_changed = 1;
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"mode")) {
- if (!mode)
+ if (remount)
continue;
- *mode = simple_strtoul(value,&rest,8);
+ config->mode = simple_strtoul(value, &rest, 8) & 07777;
+ config->mode_changed = 1;
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"uid")) {
- if (!uid)
+ if (remount)
continue;
- *uid = simple_strtoul(value,&rest,0);
+ config->uid = simple_strtoul(value, &rest, 0);
+ config->uid_changed = 1;
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"gid")) {
- if (!gid)
+ if (remount)
continue;
- *gid = simple_strtoul(value,&rest,0);
+ config->gid = simple_strtoul(value, &rest, 0);
+ config->gid_changed = 1;
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"mpol")) {
- if (shmem_parse_mpol(value,policy,policy_nodes))
+ if (shmem_parse_mpol(value, &config->policy,
+ &config->policy_nodes))
goto bad_val;
} else {
printk(KERN_ERR "tmpfs: Bad mount option %s\n",
@@ -2170,24 +2179,20 @@ bad_val:
static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- unsigned long max_blocks = sbinfo->max_blocks;
- unsigned long max_inodes = sbinfo->max_inodes;
- int policy = sbinfo->policy;
- nodemask_t policy_nodes = sbinfo->policy_nodes;
+ struct shmem_config config = sbinfo->config;
unsigned long blocks;
unsigned long inodes;
int error = -EINVAL;
- if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks,
- &max_inodes, &policy, &policy_nodes))
+ if (shmem_parse_options(data, &config, true))
return error;
spin_lock(&sbinfo->stat_lock);
- blocks = sbinfo->max_blocks - sbinfo->free_blocks;
- inodes = sbinfo->max_inodes - sbinfo->free_inodes;
- if (max_blocks < blocks)
+ blocks = sbinfo->config.max_blocks - sbinfo->free_blocks;
+ inodes = sbinfo->config.max_inodes - sbinfo->free_inodes;
+ if (config.max_blocks < blocks)
goto out;
- if (max_inodes < inodes)
+ if (config.max_inodes < inodes)
goto out;
/*
* Those tests also disallow limited->unlimited while any are in
@@ -2195,24 +2200,85 @@ static int shmem_remount_fs(struct super
* but we must separately disallow unlimited->limited, because
* in that case we have no record of how much is already in use.
*/
- if (max_blocks && !sbinfo->max_blocks)
+ if (config.max_blocks && !sbinfo->config.max_blocks)
goto out;
- if (max_inodes && !sbinfo->max_inodes)
+ if (config.max_inodes && !sbinfo->config.max_inodes)
goto out;
error = 0;
- sbinfo->max_blocks = max_blocks;
- sbinfo->free_blocks = max_blocks - blocks;
- sbinfo->max_inodes = max_inodes;
- sbinfo->free_inodes = max_inodes - inodes;
- sbinfo->policy = policy;
- sbinfo->policy_nodes = policy_nodes;
+ sbinfo->config = config;
+ sbinfo->free_blocks = config.max_blocks - blocks;
+ sbinfo->free_inodes = config.max_inodes - inodes;
out:
spin_unlock(&sbinfo->stat_lock);
return error;
}
+
+#ifdef CONFIG_NUMA
+static void shmem_show_mpol(struct seq_file *seq, int policy,
+ const nodemask_t policy_nodes)
+{
+ seq_puts(seq, ",mpol=");
+ switch (policy) {
+ case MPOL_PREFERRED:
+ seq_puts(seq, "default");
+ break;
+ case MPOL_BIND:
+ seq_puts(seq, "bind");
+ break;
+ case MPOL_INTERLEAVE:
+ seq_puts(seq, "interleave");
+ break;
+ default:
+ seq_puts(seq, "default");
+ }
+
+ if (policy == MPOL_PREFERRED || policy == MPOL_BIND ||
+ (policy == MPOL_INTERLEAVE &&
+ !nodes_equal(policy_nodes, node_online_map))) {
+ char buffer[64];
+ int len;
+
+ len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes);
+ if (len < sizeof(buffer))
+ seq_printf(seq, ":%s", buffer);
+ else
+ seq_printf(seq, ":?");
+ }
+}
+#else
+static void shmem_show_mpol(struct seq_file *seq, int policy,
+ const nodemask_t policy_nodes)
+{
+}
#endif
+static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct super_block *sb = vfs->mnt_sb;
+ struct shmem_config *config = &SHMEM_SB(sb)->config;
+
+ if (config->max_blocks_changed) {
+ unsigned long sizek;
+
+ sizek = config->max_blocks << (PAGE_CACHE_SHIFT - 10);
+ seq_printf(seq, ",size=%luk", sizek);
+ }
+ if (config->max_inodes_changed)
+ seq_printf(seq, ",nr_inodes=%lu", config->max_inodes);
+ if (config->mode_changed)
+ seq_printf(seq, ",mode=%03o", config->mode);
+ if (config->uid_changed)
+ seq_printf(seq, ",uid=%u", config->uid);
+ if (config->gid_changed)
+ seq_printf(seq, ",gid=%u", config->gid);
+ if (config->policy != MPOL_DEFAULT)
+ shmem_show_mpol(seq, config->policy, config->policy_nodes);
+
+ return 0;
+}
+#endif /* CONFIG_TMPFS */
+
static void shmem_put_super(struct super_block *sb)
{
kfree(sb->s_fs_info);
@@ -2224,15 +2290,17 @@ static int shmem_fill_super(struct super
{
struct inode *inode;
struct dentry *root;
- int mode = S_IRWXUGO | S_ISVTX;
- uid_t uid = current->fsuid;
- gid_t gid = current->fsgid;
int err = -ENOMEM;
struct shmem_sb_info *sbinfo;
- unsigned long blocks = 0;
- unsigned long inodes = 0;
- int policy = MPOL_DEFAULT;
- nodemask_t policy_nodes = node_states[N_HIGH_MEMORY];
+ struct shmem_config config = {
+ .mode = S_IRWXUGO | S_ISVTX,
+ .uid = current->fsuid,
+ .gid = current->fsgid,
+ .max_blocks = 0,
+ .max_inodes = 0,
+ .policy = MPOL_DEFAULT,
+ .policy_nodes = node_states[N_HIGH_MEMORY],
+ };
#ifdef CONFIG_TMPFS
/*
@@ -2241,12 +2309,11 @@ static int shmem_fill_super(struct super
* but the internal instance is left unlimited.
*/
if (!(sb->s_flags & MS_NOUSER)) {
- blocks = totalram_pages / 2;
- inodes = totalram_pages - totalhigh_pages;
- if (inodes > blocks)
- inodes = blocks;
- if (shmem_parse_options(data, &mode, &uid, &gid, &blocks,
- &inodes, &policy, &policy_nodes))
+ config.max_blocks = totalram_pages / 2;
+ config.max_inodes = totalram_pages - totalhigh_pages;
+ if (config.max_inodes > config.max_blocks)
+ config.max_inodes = config.max_blocks;
+ if (shmem_parse_options(data, &config, false))
return -EINVAL;
}
sb->s_export_op = &shmem_export_ops;
@@ -2261,12 +2328,9 @@ static int shmem_fill_super(struct super
return -ENOMEM;
spin_lock_init(&sbinfo->stat_lock);
- sbinfo->max_blocks = blocks;
- sbinfo->free_blocks = blocks;
- sbinfo->max_inodes = inodes;
- sbinfo->free_inodes = inodes;
- sbinfo->policy = policy;
- sbinfo->policy_nodes = policy_nodes;
+ sbinfo->config = config;
+ sbinfo->free_blocks = config.max_blocks;
+ sbinfo->free_inodes = config.max_inodes;
sb->s_fs_info = sbinfo;
sb->s_maxbytes = SHMEM_MAX_BYTES;
@@ -2280,11 +2344,11 @@ static int shmem_fill_super(struct super
sb->s_flags |= MS_POSIXACL;
#endif
- inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
+ inode = shmem_get_inode(sb, S_IFDIR | config.mode, 0);
if (!inode)
goto failed;
- inode->i_uid = uid;
- inode->i_gid = gid;
+ inode->i_uid = config.uid;
+ inode->i_gid = config.gid;
root = d_alloc_root(inode);
if (!root)
goto failed_iput;
@@ -2420,6 +2484,7 @@ static const struct super_operations shm
#ifdef CONFIG_TMPFS
.statfs = shmem_statfs,
.remount_fs = shmem_remount_fs,
+ .show_options = shmem_show_options,
#endif
.delete_inode = shmem_delete_inode,
.drop_inode = generic_delete_inode,
Index: linux/include/linux/shmem_fs.h
===================================================================
--- linux.orig/include/linux/shmem_fs.h 2008-01-21 21:20:04.000000000 +0100
+++ linux/include/linux/shmem_fs.h 2008-01-21 21:21:08.000000000 +0100
@@ -25,14 +25,27 @@ struct shmem_inode_info {
#endif
};
-struct shmem_sb_info {
+struct shmem_config {
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
unsigned long max_blocks; /* How many blocks are allowed */
- unsigned long free_blocks; /* How many are left for allocation */
unsigned long max_inodes; /* How many inodes are allowed */
- unsigned long free_inodes; /* How many are left for allocation */
int policy; /* Default NUMA memory alloc policy */
nodemask_t policy_nodes; /* nodemask for preferred and bind */
+
+ unsigned mode_changed : 1;
+ unsigned uid_changed : 1;
+ unsigned gid_changed : 1;
+ unsigned max_blocks_changed : 1;
+ unsigned max_inodes_changed : 1;
+};
+
+struct shmem_sb_info {
+ unsigned long free_blocks; /* How many are left for allocation */
+ unsigned long free_inodes; /* How many are left for allocation */
spinlock_t stat_lock;
+ struct shmem_config config;
};
static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
--
On Thu, 24 Jan 2008, Miklos Szeredi wrote:
>
Thanks Miklos, that's a welcome enhancement, nicely done. I've only
noticed one thing wrong (MPOL_PREFERRED shown as "default"); but thought
shmem_config didn't add much value - I'd rather avoid those syntactic
changes to unchanged code; and several tmpfs defaults being relative
(e.g. to totalram_pages, or to mounter's fsuid), I ended up preferring
to do real tests in shmem_show_options.
Thus, for example, if memory is hotplugged in or out later, what started
out as an unspecified size option will then get shown as explicit size.
(I did think for a while that I wanted to show explicit size in all
cases; but it looked pretty silly on udev.) I think that's the correct
behaviour, that otherwise would be misleading; but I may be looking at
this the wrong way round, what's your view?
If you agree with the version below, please take it into your collection
and insert your Signed-off-by. I should admit, I've not yet tested how
the NUMA policies look: you'll hear from me again tomorrow morning if
those turn out to wrong.
Hugh
From: Miklos Szeredi <[email protected]>
Add .show_options super operation to tmpfs.
Signed-off-by: Hugh Dickins <[email protected]>
---
include/linux/shmem_fs.h | 5
mm/shmem.c | 189 ++++++++++++++++++++++++-------------
2 files changed, 129 insertions(+), 65 deletions(-)
--- 2.6.24-rc8-mm1/include/linux/shmem_fs.h 2006-11-29 21:57:37.000000000 +0000
+++ linux/include/linux/shmem_fs.h 2008-01-27 22:42:52.000000000 +0000
@@ -30,9 +30,12 @@ struct shmem_sb_info {
unsigned long free_blocks; /* How many are left for allocation */
unsigned long max_inodes; /* How many inodes are allowed */
unsigned long free_inodes; /* How many are left for allocation */
+ spinlock_t stat_lock; /* Serialize shmem_sb_info changes */
+ uid_t uid; /* Mount uid for root directory */
+ gid_t gid; /* Mount gid for root directory */
+ mode_t mode; /* Mount mode for root directory */
int policy; /* Default NUMA memory alloc policy */
nodemask_t policy_nodes; /* nodemask for preferred and bind */
- spinlock_t stat_lock;
};
static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
--- 2.6.24-rc8-mm1/mm/shmem.c 2008-01-17 16:51:21.000000000 +0000
+++ linux/mm/shmem.c 2008-01-27 23:41:31.000000000 +0000
@@ -49,6 +49,7 @@
#include <linux/ctype.h>
#include <linux/migrate.h>
#include <linux/highmem.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
@@ -1068,7 +1069,8 @@ redirty:
}
#ifdef CONFIG_NUMA
-static inline int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes)
+#ifdef CONFIG_TMPFS
+static int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes)
{
char *nodelist = strchr(value, ':');
int err = 1;
@@ -1117,6 +1119,42 @@ out:
return err;
}
+static void shmem_show_mpol(struct seq_file *seq, int policy,
+ const nodemask_t policy_nodes)
+{
+ char *policy_string;
+
+ switch (policy) {
+ case MPOL_PREFERRED:
+ policy_string = "prefer";
+ break;
+ case MPOL_BIND:
+ policy_string = "bind";
+ break;
+ case MPOL_INTERLEAVE:
+ policy_string = "interleave";
+ break;
+ default:
+ /* MPOL_DEFAULT */
+ return;
+ }
+
+ seq_printf(seq, ",mpol=%s", policy_string);
+
+ if (policy != MPOL_INTERLEAVE ||
+ !nodes_equal(policy_nodes, node_states[N_HIGH_MEMORY])) {
+ char buffer[64];
+ int len;
+
+ len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes);
+ if (len < sizeof(buffer))
+ seq_printf(seq, ":%s", buffer);
+ else
+ seq_printf(seq, ":?");
+ }
+}
+#endif /* CONFIG_TMPFS */
+
static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
struct shmem_inode_info *info, unsigned long idx)
{
@@ -1148,13 +1186,20 @@ static struct page *shmem_alloc_page(gfp
mpol_free(pvma.vm_policy);
return page;
}
-#else
+#else /* !CONFIG_NUMA */
+#ifdef CONFIG_TMPFS
static inline int shmem_parse_mpol(char *value, int *policy,
nodemask_t *policy_nodes)
{
return 1;
}
+static inline void shmem_show_mpol(struct seq_file *seq, int policy,
+ const nodemask_t policy_nodes)
+{
+}
+#endif /* CONFIG_TMPFS */
+
static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
struct shmem_inode_info *info, unsigned long idx)
{
@@ -1166,7 +1211,7 @@ static inline struct page *shmem_alloc_p
{
return alloc_page(gfp);
}
-#endif
+#endif /* CONFIG_NUMA */
/*
* shmem_getpage - either get the page from swap or allocate a new one
@@ -2077,9 +2122,8 @@ static const struct export_operations sh
.fh_to_dentry = shmem_fh_to_dentry,
};
-static int shmem_parse_options(char *options, int *mode, uid_t *uid,
- gid_t *gid, unsigned long *blocks, unsigned long *inodes,
- int *policy, nodemask_t *policy_nodes)
+static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
+ bool remount)
{
char *this_char, *value, *rest;
@@ -2122,35 +2166,37 @@ static int shmem_parse_options(char *opt
}
if (*rest)
goto bad_val;
- *blocks = DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
+ sbinfo->max_blocks =
+ DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
} else if (!strcmp(this_char,"nr_blocks")) {
- *blocks = memparse(value,&rest);
+ sbinfo->max_blocks = memparse(value, &rest);
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"nr_inodes")) {
- *inodes = memparse(value,&rest);
+ sbinfo->max_inodes = memparse(value, &rest);
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"mode")) {
- if (!mode)
+ if (remount)
continue;
- *mode = simple_strtoul(value,&rest,8);
+ sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"uid")) {
- if (!uid)
+ if (remount)
continue;
- *uid = simple_strtoul(value,&rest,0);
+ sbinfo->uid = simple_strtoul(value, &rest, 0);
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"gid")) {
- if (!gid)
+ if (remount)
continue;
- *gid = simple_strtoul(value,&rest,0);
+ sbinfo->gid = simple_strtoul(value, &rest, 0);
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"mpol")) {
- if (shmem_parse_mpol(value,policy,policy_nodes))
+ if (shmem_parse_mpol(value, &sbinfo->policy,
+ &sbinfo->policy_nodes))
goto bad_val;
} else {
printk(KERN_ERR "tmpfs: Bad mount option %s\n",
@@ -2170,24 +2216,20 @@ bad_val:
static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
{
struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
- unsigned long max_blocks = sbinfo->max_blocks;
- unsigned long max_inodes = sbinfo->max_inodes;
- int policy = sbinfo->policy;
- nodemask_t policy_nodes = sbinfo->policy_nodes;
+ struct shmem_sb_info config = *sbinfo;
unsigned long blocks;
unsigned long inodes;
int error = -EINVAL;
- if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks,
- &max_inodes, &policy, &policy_nodes))
+ if (shmem_parse_options(data, &config, true))
return error;
spin_lock(&sbinfo->stat_lock);
blocks = sbinfo->max_blocks - sbinfo->free_blocks;
inodes = sbinfo->max_inodes - sbinfo->free_inodes;
- if (max_blocks < blocks)
+ if (config.max_blocks < blocks)
goto out;
- if (max_inodes < inodes)
+ if (config.max_inodes < inodes)
goto out;
/*
* Those tests also disallow limited->unlimited while any are in
@@ -2195,23 +2237,43 @@ static int shmem_remount_fs(struct super
* but we must separately disallow unlimited->limited, because
* in that case we have no record of how much is already in use.
*/
- if (max_blocks && !sbinfo->max_blocks)
+ if (config.max_blocks && !sbinfo->max_blocks)
goto out;
- if (max_inodes && !sbinfo->max_inodes)
+ if (config.max_inodes && !sbinfo->max_inodes)
goto out;
error = 0;
- sbinfo->max_blocks = max_blocks;
- sbinfo->free_blocks = max_blocks - blocks;
- sbinfo->max_inodes = max_inodes;
- sbinfo->free_inodes = max_inodes - inodes;
- sbinfo->policy = policy;
- sbinfo->policy_nodes = policy_nodes;
+ sbinfo->max_blocks = config.max_blocks;
+ sbinfo->free_blocks = config.max_blocks - blocks;
+ sbinfo->max_inodes = config.max_inodes;
+ sbinfo->free_inodes = config.max_inodes - inodes;
+ sbinfo->policy = config.policy;
+ sbinfo->policy_nodes = config.policy_nodes;
out:
spin_unlock(&sbinfo->stat_lock);
return error;
}
-#endif
+
+static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct shmem_sb_info *sbinfo = SHMEM_SB(vfs->mnt_sb);
+
+ if (sbinfo->max_blocks != totalram_pages / 2)
+ seq_printf(seq, ",size=%luk",
+ sbinfo->max_blocks << (PAGE_CACHE_SHIFT - 10));
+ if (sbinfo->max_inodes !=
+ min(totalram_pages - totalhigh_pages, totalram_pages / 2))
+ seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
+ if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
+ seq_printf(seq, ",mode=%03o", sbinfo->mode);
+ if (sbinfo->uid != 0)
+ seq_printf(seq, ",uid=%u", sbinfo->uid);
+ if (sbinfo->gid != 0)
+ seq_printf(seq, ",gid=%u", sbinfo->gid);
+ shmem_show_mpol(seq, sbinfo->policy, sbinfo->policy_nodes);
+ return 0;
+}
+#endif /* CONFIG_TMPFS */
static void shmem_put_super(struct super_block *sb)
{
@@ -2224,15 +2286,23 @@ static int shmem_fill_super(struct super
{
struct inode *inode;
struct dentry *root;
- int mode = S_IRWXUGO | S_ISVTX;
- uid_t uid = current->fsuid;
- gid_t gid = current->fsgid;
- int err = -ENOMEM;
struct shmem_sb_info *sbinfo;
- unsigned long blocks = 0;
- unsigned long inodes = 0;
- int policy = MPOL_DEFAULT;
- nodemask_t policy_nodes = node_states[N_HIGH_MEMORY];
+ int err = -ENOMEM;
+
+ /* Round up to L1_CACHE_BYTES to resist false sharing */
+ sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info),
+ L1_CACHE_BYTES), GFP_KERNEL);
+ if (!sbinfo)
+ return -ENOMEM;
+
+ sbinfo->max_blocks = 0;
+ sbinfo->max_inodes = 0;
+ sbinfo->mode = S_IRWXUGO | S_ISVTX;
+ sbinfo->uid = current->fsuid;
+ sbinfo->gid = current->fsgid;
+ sbinfo->policy = MPOL_DEFAULT;
+ sbinfo->policy_nodes = node_states[N_HIGH_MEMORY];
+ sb->s_fs_info = sbinfo;
#ifdef CONFIG_TMPFS
/*
@@ -2241,34 +2311,24 @@ static int shmem_fill_super(struct super
* but the internal instance is left unlimited.
*/
if (!(sb->s_flags & MS_NOUSER)) {
- blocks = totalram_pages / 2;
- inodes = totalram_pages - totalhigh_pages;
- if (inodes > blocks)
- inodes = blocks;
- if (shmem_parse_options(data, &mode, &uid, &gid, &blocks,
- &inodes, &policy, &policy_nodes))
- return -EINVAL;
+ sbinfo->max_blocks = totalram_pages / 2;
+ sbinfo->max_inodes = totalram_pages - totalhigh_pages;
+ if (sbinfo->max_inodes > sbinfo->max_blocks)
+ sbinfo->max_inodes = sbinfo->max_blocks;
+ if (shmem_parse_options(data, sbinfo, false)) {
+ err = -EINVAL;
+ goto failed;
+ }
}
sb->s_export_op = &shmem_export_ops;
#else
sb->s_flags |= MS_NOUSER;
#endif
- /* Round up to L1_CACHE_BYTES to resist false sharing */
- sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info),
- L1_CACHE_BYTES), GFP_KERNEL);
- if (!sbinfo)
- return -ENOMEM;
-
spin_lock_init(&sbinfo->stat_lock);
- sbinfo->max_blocks = blocks;
- sbinfo->free_blocks = blocks;
- sbinfo->max_inodes = inodes;
- sbinfo->free_inodes = inodes;
- sbinfo->policy = policy;
- sbinfo->policy_nodes = policy_nodes;
+ sbinfo->free_blocks = sbinfo->max_blocks;
+ sbinfo->free_inodes = sbinfo->max_inodes;
- sb->s_fs_info = sbinfo;
sb->s_maxbytes = SHMEM_MAX_BYTES;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -2280,11 +2340,11 @@ static int shmem_fill_super(struct super
sb->s_flags |= MS_POSIXACL;
#endif
- inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
+ inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0);
if (!inode)
goto failed;
- inode->i_uid = uid;
- inode->i_gid = gid;
+ inode->i_uid = sbinfo->uid;
+ inode->i_gid = sbinfo->gid;
root = d_alloc_root(inode);
if (!root)
goto failed_iput;
@@ -2420,6 +2480,7 @@ static const struct super_operations shm
#ifdef CONFIG_TMPFS
.statfs = shmem_statfs,
.remount_fs = shmem_remount_fs,
+ .show_options = shmem_show_options,
#endif
.delete_inode = shmem_delete_inode,
.drop_inode = generic_delete_inode,
>
> Thanks Miklos, that's a welcome enhancement, nicely done. I've only
> noticed one thing wrong (MPOL_PREFERRED shown as "default"); but thought
> shmem_config didn't add much value - I'd rather avoid those syntactic
> changes to unchanged code; and several tmpfs defaults being relative
> (e.g. to totalram_pages, or to mounter's fsuid), I ended up preferring
> to do real tests in shmem_show_options.
I completely agree, this is much better than my version.
> Thus, for example, if memory is hotplugged in or out later, what started
> out as an unspecified size option will then get shown as explicit size.
> (I did think for a while that I wanted to show explicit size in all
> cases; but it looked pretty silly on udev.) I think that's the correct
> behaviour, that otherwise would be misleading; but I may be looking at
> this the wrong way round, what's your view?
I agree, this is the correct way.
I'll add functions for calculating the default max values, so the
calculations won't accidentally become different for the
initialization and the option showing.
> If you agree with the version below, please take it into your collection
> and insert your Signed-off-by. I should admit, I've not yet tested how
> the NUMA policies look: you'll hear from me again tomorrow morning if
> those turn out to wrong.
OK, I'll send this to Andrew. Maybe I'll wait until tomorrow to hear
if it's working on NUMA.
Thanks,
Miklos
On Mon, 28 Jan 2008, Miklos Szeredi wrote:
>
> I'll add functions for calculating the default max values, so the
> calculations won't accidentally become different for the
> initialization and the option showing.
Excellent.
> > If you agree with the version below, please take it into your collection
> > and insert your Signed-off-by. I should admit, I've not yet tested how
> > the NUMA policies look: you'll hear from me again tomorrow morning if
> > those turn out to wrong.
>
> OK, I'll send this to Andrew. Maybe I'll wait until tomorrow to hear
> if it's working on NUMA.
I've just now checked: the NUMA options are showing fine.
Thanks,
Hugh