[patch 24/26] mount options: fix tmpfs

From: Miklos Szeredi
Date: Thu Jan 24 2008 - 14:42:00 EST


From: Miklos Szeredi <mszeredi@xxxxxxx>

Add .show_options super operation to tmpfs.

Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxx>
---

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)

--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/