From: Miklos Szeredi Add .show_options super operation to tmpfs. Signed-off-by: Miklos Szeredi --- 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 #include #include +#include #include #include @@ -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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/