aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakpm@linux-foundation.org <akpm@linux-foundation.org>2008-02-08 07:21:48 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:41 -0500
commit680d794babebc74484c141448baa9b95b211cf5e (patch)
treefa8b9c085fceaed12b54ea20a8c04696c750053e
parent90d09e141bb23bf0df5e31c40fb3175c17e8bda2 (diff)
mount options: fix tmpfs
Add .show_options super operation to tmpfs. Signed-off-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/shmem_fs.h5
-rw-r--r--mm/shmem.c196
2 files changed, 136 insertions, 65 deletions
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index f3c51899117f..8d5fb36ea047 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -30,9 +30,12 @@ struct shmem_sb_info {
30 unsigned long free_blocks; /* How many are left for allocation */ 30 unsigned long free_blocks; /* How many are left for allocation */
31 unsigned long max_inodes; /* How many inodes are allowed */ 31 unsigned long max_inodes; /* How many inodes are allowed */
32 unsigned long free_inodes; /* How many are left for allocation */ 32 unsigned long free_inodes; /* How many are left for allocation */
33 spinlock_t stat_lock; /* Serialize shmem_sb_info changes */
34 uid_t uid; /* Mount uid for root directory */
35 gid_t gid; /* Mount gid for root directory */
36 mode_t mode; /* Mount mode for root directory */
33 int policy; /* Default NUMA memory alloc policy */ 37 int policy; /* Default NUMA memory alloc policy */
34 nodemask_t policy_nodes; /* nodemask for preferred and bind */ 38 nodemask_t policy_nodes; /* nodemask for preferred and bind */
35 spinlock_t stat_lock;
36}; 39};
37 40
38static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) 41static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
diff --git a/mm/shmem.c b/mm/shmem.c
index 85bed948fafc..2f961a6dbf57 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -49,6 +49,7 @@
49#include <linux/ctype.h> 49#include <linux/ctype.h>
50#include <linux/migrate.h> 50#include <linux/migrate.h>
51#include <linux/highmem.h> 51#include <linux/highmem.h>
52#include <linux/seq_file.h>
52 53
53#include <asm/uaccess.h> 54#include <asm/uaccess.h>
54#include <asm/div64.h> 55#include <asm/div64.h>
@@ -84,6 +85,16 @@ enum sgp_type {
84 SGP_WRITE, /* may exceed i_size, may allocate page */ 85 SGP_WRITE, /* may exceed i_size, may allocate page */
85}; 86};
86 87
88static unsigned long shmem_default_max_blocks(void)
89{
90 return totalram_pages / 2;
91}
92
93static unsigned long shmem_default_max_inodes(void)
94{
95 return min(totalram_pages - totalhigh_pages, totalram_pages / 2);
96}
97
87static int shmem_getpage(struct inode *inode, unsigned long idx, 98static int shmem_getpage(struct inode *inode, unsigned long idx,
88 struct page **pagep, enum sgp_type sgp, int *type); 99 struct page **pagep, enum sgp_type sgp, int *type);
89 100
@@ -1068,7 +1079,8 @@ redirty:
1068} 1079}
1069 1080
1070#ifdef CONFIG_NUMA 1081#ifdef CONFIG_NUMA
1071static inline int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes) 1082#ifdef CONFIG_TMPFS
1083static int shmem_parse_mpol(char *value, int *policy, nodemask_t *policy_nodes)
1072{ 1084{
1073 char *nodelist = strchr(value, ':'); 1085 char *nodelist = strchr(value, ':');
1074 int err = 1; 1086 int err = 1;
@@ -1117,6 +1129,42 @@ out:
1117 return err; 1129 return err;
1118} 1130}
1119 1131
1132static void shmem_show_mpol(struct seq_file *seq, int policy,
1133 const nodemask_t policy_nodes)
1134{
1135 char *policy_string;
1136
1137 switch (policy) {
1138 case MPOL_PREFERRED:
1139 policy_string = "prefer";
1140 break;
1141 case MPOL_BIND:
1142 policy_string = "bind";
1143 break;
1144 case MPOL_INTERLEAVE:
1145 policy_string = "interleave";
1146 break;
1147 default:
1148 /* MPOL_DEFAULT */
1149 return;
1150 }
1151
1152 seq_printf(seq, ",mpol=%s", policy_string);
1153
1154 if (policy != MPOL_INTERLEAVE ||
1155 !nodes_equal(policy_nodes, node_states[N_HIGH_MEMORY])) {
1156 char buffer[64];
1157 int len;
1158
1159 len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes);
1160 if (len < sizeof(buffer))
1161 seq_printf(seq, ":%s", buffer);
1162 else
1163 seq_printf(seq, ":?");
1164 }
1165}
1166#endif /* CONFIG_TMPFS */
1167
1120static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp, 1168static struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
1121 struct shmem_inode_info *info, unsigned long idx) 1169 struct shmem_inode_info *info, unsigned long idx)
1122{ 1170{
@@ -1148,13 +1196,20 @@ static struct page *shmem_alloc_page(gfp_t gfp,
1148 mpol_free(pvma.vm_policy); 1196 mpol_free(pvma.vm_policy);
1149 return page; 1197 return page;
1150} 1198}
1151#else 1199#else /* !CONFIG_NUMA */
1200#ifdef CONFIG_TMPFS
1152static inline int shmem_parse_mpol(char *value, int *policy, 1201static inline int shmem_parse_mpol(char *value, int *policy,
1153 nodemask_t *policy_nodes) 1202 nodemask_t *policy_nodes)
1154{ 1203{
1155 return 1; 1204 return 1;
1156} 1205}
1157 1206
1207static inline void shmem_show_mpol(struct seq_file *seq, int policy,
1208 const nodemask_t policy_nodes)
1209{
1210}
1211#endif /* CONFIG_TMPFS */
1212
1158static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp, 1213static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
1159 struct shmem_inode_info *info, unsigned long idx) 1214 struct shmem_inode_info *info, unsigned long idx)
1160{ 1215{
@@ -1166,7 +1221,7 @@ static inline struct page *shmem_alloc_page(gfp_t gfp,
1166{ 1221{
1167 return alloc_page(gfp); 1222 return alloc_page(gfp);
1168} 1223}
1169#endif 1224#endif /* CONFIG_NUMA */
1170 1225
1171/* 1226/*
1172 * shmem_getpage - either get the page from swap or allocate a new one 1227 * shmem_getpage - either get the page from swap or allocate a new one
@@ -2077,9 +2132,8 @@ static const struct export_operations shmem_export_ops = {
2077 .fh_to_dentry = shmem_fh_to_dentry, 2132 .fh_to_dentry = shmem_fh_to_dentry,
2078}; 2133};
2079 2134
2080static int shmem_parse_options(char *options, int *mode, uid_t *uid, 2135static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
2081 gid_t *gid, unsigned long *blocks, unsigned long *inodes, 2136 bool remount)
2082 int *policy, nodemask_t *policy_nodes)
2083{ 2137{
2084 char *this_char, *value, *rest; 2138 char *this_char, *value, *rest;
2085 2139
@@ -2122,35 +2176,37 @@ static int shmem_parse_options(char *options, int *mode, uid_t *uid,
2122 } 2176 }
2123 if (*rest) 2177 if (*rest)
2124 goto bad_val; 2178 goto bad_val;
2125 *blocks = DIV_ROUND_UP(size, PAGE_CACHE_SIZE); 2179 sbinfo->max_blocks =
2180 DIV_ROUND_UP(size, PAGE_CACHE_SIZE);
2126 } else if (!strcmp(this_char,"nr_blocks")) { 2181 } else if (!strcmp(this_char,"nr_blocks")) {
2127 *blocks = memparse(value,&rest); 2182 sbinfo->max_blocks = memparse(value, &rest);
2128 if (*rest) 2183 if (*rest)
2129 goto bad_val; 2184 goto bad_val;
2130 } else if (!strcmp(this_char,"nr_inodes")) { 2185 } else if (!strcmp(this_char,"nr_inodes")) {
2131 *inodes = memparse(value,&rest); 2186 sbinfo->max_inodes = memparse(value, &rest);
2132 if (*rest) 2187 if (*rest)
2133 goto bad_val; 2188 goto bad_val;
2134 } else if (!strcmp(this_char,"mode")) { 2189 } else if (!strcmp(this_char,"mode")) {
2135 if (!mode) 2190 if (remount)
2136 continue; 2191 continue;
2137 *mode = simple_strtoul(value,&rest,8); 2192 sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777;
2138 if (*rest) 2193 if (*rest)
2139 goto bad_val; 2194 goto bad_val;
2140 } else if (!strcmp(this_char,"uid")) { 2195 } else if (!strcmp(this_char,"uid")) {
2141 if (!uid) 2196 if (remount)
2142 continue; 2197 continue;
2143 *uid = simple_strtoul(value,&rest,0); 2198 sbinfo->uid = simple_strtoul(value, &rest, 0);
2144 if (*rest) 2199 if (*rest)
2145 goto bad_val; 2200 goto bad_val;
2146 } else if (!strcmp(this_char,"gid")) { 2201 } else if (!strcmp(this_char,"gid")) {
2147 if (!gid) 2202 if (remount)
2148 continue; 2203 continue;
2149 *gid = simple_strtoul(value,&rest,0); 2204 sbinfo->gid = simple_strtoul(value, &rest, 0);
2150 if (*rest) 2205 if (*rest)
2151 goto bad_val; 2206 goto bad_val;
2152 } else if (!strcmp(this_char,"mpol")) { 2207 } else if (!strcmp(this_char,"mpol")) {
2153 if (shmem_parse_mpol(value,policy,policy_nodes)) 2208 if (shmem_parse_mpol(value, &sbinfo->policy,
2209 &sbinfo->policy_nodes))
2154 goto bad_val; 2210 goto bad_val;
2155 } else { 2211 } else {
2156 printk(KERN_ERR "tmpfs: Bad mount option %s\n", 2212 printk(KERN_ERR "tmpfs: Bad mount option %s\n",
@@ -2170,24 +2226,20 @@ bad_val:
2170static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) 2226static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
2171{ 2227{
2172 struct shmem_sb_info *sbinfo = SHMEM_SB(sb); 2228 struct shmem_sb_info *sbinfo = SHMEM_SB(sb);
2173 unsigned long max_blocks = sbinfo->max_blocks; 2229 struct shmem_sb_info config = *sbinfo;
2174 unsigned long max_inodes = sbinfo->max_inodes;
2175 int policy = sbinfo->policy;
2176 nodemask_t policy_nodes = sbinfo->policy_nodes;
2177 unsigned long blocks; 2230 unsigned long blocks;
2178 unsigned long inodes; 2231 unsigned long inodes;
2179 int error = -EINVAL; 2232 int error = -EINVAL;
2180 2233
2181 if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks, 2234 if (shmem_parse_options(data, &config, true))
2182 &max_inodes, &policy, &policy_nodes))
2183 return error; 2235 return error;
2184 2236
2185 spin_lock(&sbinfo->stat_lock); 2237 spin_lock(&sbinfo->stat_lock);
2186 blocks = sbinfo->max_blocks - sbinfo->free_blocks; 2238 blocks = sbinfo->max_blocks - sbinfo->free_blocks;
2187 inodes = sbinfo->max_inodes - sbinfo->free_inodes; 2239 inodes = sbinfo->max_inodes - sbinfo->free_inodes;
2188 if (max_blocks < blocks) 2240 if (config.max_blocks < blocks)
2189 goto out; 2241 goto out;
2190 if (max_inodes < inodes) 2242 if (config.max_inodes < inodes)
2191 goto out; 2243 goto out;
2192 /* 2244 /*
2193 * Those tests also disallow limited->unlimited while any are in 2245 * Those tests also disallow limited->unlimited while any are in
@@ -2195,23 +2247,42 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data)
2195 * but we must separately disallow unlimited->limited, because 2247 * but we must separately disallow unlimited->limited, because
2196 * in that case we have no record of how much is already in use. 2248 * in that case we have no record of how much is already in use.
2197 */ 2249 */
2198 if (max_blocks && !sbinfo->max_blocks) 2250 if (config.max_blocks && !sbinfo->max_blocks)
2199 goto out; 2251 goto out;
2200 if (max_inodes && !sbinfo->max_inodes) 2252 if (config.max_inodes && !sbinfo->max_inodes)
2201 goto out; 2253 goto out;
2202 2254
2203 error = 0; 2255 error = 0;
2204 sbinfo->max_blocks = max_blocks; 2256 sbinfo->max_blocks = config.max_blocks;
2205 sbinfo->free_blocks = max_blocks - blocks; 2257 sbinfo->free_blocks = config.max_blocks - blocks;
2206 sbinfo->max_inodes = max_inodes; 2258 sbinfo->max_inodes = config.max_inodes;
2207 sbinfo->free_inodes = max_inodes - inodes; 2259 sbinfo->free_inodes = config.max_inodes - inodes;
2208 sbinfo->policy = policy; 2260 sbinfo->policy = config.policy;
2209 sbinfo->policy_nodes = policy_nodes; 2261 sbinfo->policy_nodes = config.policy_nodes;
2210out: 2262out:
2211 spin_unlock(&sbinfo->stat_lock); 2263 spin_unlock(&sbinfo->stat_lock);
2212 return error; 2264 return error;
2213} 2265}
2214#endif 2266
2267static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs)
2268{
2269 struct shmem_sb_info *sbinfo = SHMEM_SB(vfs->mnt_sb);
2270
2271 if (sbinfo->max_blocks != shmem_default_max_blocks())
2272 seq_printf(seq, ",size=%luk",
2273 sbinfo->max_blocks << (PAGE_CACHE_SHIFT - 10));
2274 if (sbinfo->max_inodes != shmem_default_max_inodes())
2275 seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
2276 if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
2277 seq_printf(seq, ",mode=%03o", sbinfo->mode);
2278 if (sbinfo->uid != 0)
2279 seq_printf(seq, ",uid=%u", sbinfo->uid);
2280 if (sbinfo->gid != 0)
2281 seq_printf(seq, ",gid=%u", sbinfo->gid);
2282 shmem_show_mpol(seq, sbinfo->policy, sbinfo->policy_nodes);
2283 return 0;
2284}
2285#endif /* CONFIG_TMPFS */
2215 2286
2216static void shmem_put_super(struct super_block *sb) 2287static void shmem_put_super(struct super_block *sb)
2217{ 2288{
@@ -2224,15 +2295,23 @@ static int shmem_fill_super(struct super_block *sb,
2224{ 2295{
2225 struct inode *inode; 2296 struct inode *inode;
2226 struct dentry *root; 2297 struct dentry *root;
2227 int mode = S_IRWXUGO | S_ISVTX;
2228 uid_t uid = current->fsuid;
2229 gid_t gid = current->fsgid;
2230 int err = -ENOMEM;
2231 struct shmem_sb_info *sbinfo; 2298 struct shmem_sb_info *sbinfo;
2232 unsigned long blocks = 0; 2299 int err = -ENOMEM;
2233 unsigned long inodes = 0; 2300
2234 int policy = MPOL_DEFAULT; 2301 /* Round up to L1_CACHE_BYTES to resist false sharing */
2235 nodemask_t policy_nodes = node_states[N_HIGH_MEMORY]; 2302 sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info),
2303 L1_CACHE_BYTES), GFP_KERNEL);
2304 if (!sbinfo)
2305 return -ENOMEM;
2306
2307 sbinfo->max_blocks = 0;
2308 sbinfo->max_inodes = 0;
2309 sbinfo->mode = S_IRWXUGO | S_ISVTX;
2310 sbinfo->uid = current->fsuid;
2311 sbinfo->gid = current->fsgid;
2312 sbinfo->policy = MPOL_DEFAULT;
2313 sbinfo->policy_nodes = node_states[N_HIGH_MEMORY];
2314 sb->s_fs_info = sbinfo;
2236 2315
2237#ifdef CONFIG_TMPFS 2316#ifdef CONFIG_TMPFS
2238 /* 2317 /*
@@ -2241,34 +2320,22 @@ static int shmem_fill_super(struct super_block *sb,
2241 * but the internal instance is left unlimited. 2320 * but the internal instance is left unlimited.
2242 */ 2321 */
2243 if (!(sb->s_flags & MS_NOUSER)) { 2322 if (!(sb->s_flags & MS_NOUSER)) {
2244 blocks = totalram_pages / 2; 2323 sbinfo->max_blocks = shmem_default_max_blocks();
2245 inodes = totalram_pages - totalhigh_pages; 2324 sbinfo->max_inodes = shmem_default_max_inodes();
2246 if (inodes > blocks) 2325 if (shmem_parse_options(data, sbinfo, false)) {
2247 inodes = blocks; 2326 err = -EINVAL;
2248 if (shmem_parse_options(data, &mode, &uid, &gid, &blocks, 2327 goto failed;
2249 &inodes, &policy, &policy_nodes)) 2328 }
2250 return -EINVAL;
2251 } 2329 }
2252 sb->s_export_op = &shmem_export_ops; 2330 sb->s_export_op = &shmem_export_ops;
2253#else 2331#else
2254 sb->s_flags |= MS_NOUSER; 2332 sb->s_flags |= MS_NOUSER;
2255#endif 2333#endif
2256 2334
2257 /* Round up to L1_CACHE_BYTES to resist false sharing */
2258 sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info),
2259 L1_CACHE_BYTES), GFP_KERNEL);
2260 if (!sbinfo)
2261 return -ENOMEM;
2262
2263 spin_lock_init(&sbinfo->stat_lock); 2335 spin_lock_init(&sbinfo->stat_lock);
2264 sbinfo->max_blocks = blocks; 2336 sbinfo->free_blocks = sbinfo->max_blocks;
2265 sbinfo->free_blocks = blocks; 2337 sbinfo->free_inodes = sbinfo->max_inodes;
2266 sbinfo->max_inodes = inodes;
2267 sbinfo->free_inodes = inodes;
2268 sbinfo->policy = policy;
2269 sbinfo->policy_nodes = policy_nodes;
2270 2338
2271 sb->s_fs_info = sbinfo;
2272 sb->s_maxbytes = SHMEM_MAX_BYTES; 2339 sb->s_maxbytes = SHMEM_MAX_BYTES;
2273 sb->s_blocksize = PAGE_CACHE_SIZE; 2340 sb->s_blocksize = PAGE_CACHE_SIZE;
2274 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 2341 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -2280,11 +2347,11 @@ static int shmem_fill_super(struct super_block *sb,
2280 sb->s_flags |= MS_POSIXACL; 2347 sb->s_flags |= MS_POSIXACL;
2281#endif 2348#endif
2282 2349
2283 inode = shmem_get_inode(sb, S_IFDIR | mode, 0); 2350 inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0);
2284 if (!inode) 2351 if (!inode)
2285 goto failed; 2352 goto failed;
2286 inode->i_uid = uid; 2353 inode->i_uid = sbinfo->uid;
2287 inode->i_gid = gid; 2354 inode->i_gid = sbinfo->gid;
2288 root = d_alloc_root(inode); 2355 root = d_alloc_root(inode);
2289 if (!root) 2356 if (!root)
2290 goto failed_iput; 2357 goto failed_iput;
@@ -2420,6 +2487,7 @@ static const struct super_operations shmem_ops = {
2420#ifdef CONFIG_TMPFS 2487#ifdef CONFIG_TMPFS
2421 .statfs = shmem_statfs, 2488 .statfs = shmem_statfs,
2422 .remount_fs = shmem_remount_fs, 2489 .remount_fs = shmem_remount_fs,
2490 .show_options = shmem_show_options,
2423#endif 2491#endif
2424 .delete_inode = shmem_delete_inode, 2492 .delete_inode = shmem_delete_inode,
2425 .drop_inode = generic_delete_inode, 2493 .drop_inode = generic_delete_inode,