Blame view

fs/efs/super.c 8.11 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
  /*
   * super.c
   *
   * Copyright (c) 1999 Al Smith
   *
   * Portions derived from work (c) 1995,1996 Christian Vogelgsang.
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
a56942551   Christoph Hellwig   knfsd: exportfs: ...
12
  #include <linux/exportfs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
  #include <linux/slab.h>
  #include <linux/buffer_head.h>
  #include <linux/vfs.h>
621c1f429   Christoph Hellwig   block: move struc...
16
  #include <linux/blkdev.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17

45254b4fb   Christoph Hellwig   efs: move headers...
18
19
20
  #include "efs.h"
  #include <linux/efs_vh.h>
  #include <linux/efs_fs_sb.h>
726c33422   David Howells   [PATCH] VFS: Perm...
21
  static int efs_statfs(struct dentry *dentry, struct kstatfs *buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  static int efs_fill_super(struct super_block *s, void *d, int silent);
152a08366   Al Viro   new helper: mount...
23
24
  static struct dentry *efs_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  {
152a08366   Al Viro   new helper: mount...
26
  	return mount_bdev(fs_type, flags, dev_name, data, efs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  }
5a9ed6f5e   Al Viro   efs: get rid of -...
28
29
30
31
32
33
  static void efs_kill_sb(struct super_block *s)
  {
  	struct efs_sb_info *sbi = SUPER_INFO(s);
  	kill_block_super(s);
  	kfree(sbi);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
  static struct file_system_type efs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "efs",
152a08366   Al Viro   new helper: mount...
37
  	.mount		= efs_mount,
5a9ed6f5e   Al Viro   efs: get rid of -...
38
  	.kill_sb	= efs_kill_sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  	.fs_flags	= FS_REQUIRES_DEV,
  };
7f78e0351   Eric W. Biederman   fs: Limit sys_mou...
41
  MODULE_ALIAS_FS("efs");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
  
  static struct pt_types sgi_pt_types[] = {
  	{0x00,		"SGI vh"},
  	{0x01,		"SGI trkrepl"},
  	{0x02,		"SGI secrepl"},
  	{0x03,		"SGI raw"},
  	{0x04,		"SGI bsd"},
  	{SGI_SYSV,	"SGI sysv"},
  	{0x06,		"SGI vol"},
  	{SGI_EFS,	"SGI efs"},
  	{0x08,		"SGI lv"},
  	{0x09,		"SGI rlv"},
  	{0x0A,		"SGI xfs"},
  	{0x0B,		"SGI xfslog"},
  	{0x0C,		"SGI xlv"},
  	{0x82,		"Linux swap"},
  	{0x83,		"Linux native"},
  	{0,		NULL}
  };
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
61
  static struct kmem_cache * efs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  
  static struct inode *efs_alloc_inode(struct super_block *sb)
  {
  	struct efs_inode_info *ei;
35a4c902f   Firo Yang   fs/efs: femove un...
66
  	ei = kmem_cache_alloc(efs_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
  	if (!ei)
  		return NULL;
  	return &ei->vfs_inode;
  }
f415c5112   Al Viro   efs: switch to ->...
71
  static void efs_free_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
  {
  	kmem_cache_free(efs_inode_cachep, INODE_INFO(inode));
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
75
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
  {
  	struct efs_inode_info *ei = (struct efs_inode_info *) foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
78
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  }
20c2df83d   Paul Mundt   mm: Remove slab d...
80

7a42d4b6a   Fabian Frederick   fs/efs/super.c: a...
81
  static int __init init_inodecache(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  {
  	efs_inode_cachep = kmem_cache_create("efs_inode_cache",
5d097056c   Vladimir Davydov   kmemcg: account c...
84
85
86
  				sizeof(struct efs_inode_info), 0,
  				SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
  				SLAB_ACCOUNT, init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
92
93
  	if (efs_inode_cachep == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void destroy_inodecache(void)
  {
8c0a85377   Kirill A. Shutemov   fs: push rcu_barr...
94
95
96
97
98
  	/*
  	 * Make sure all delayed rcu free inodes are flushed before we
  	 * destroy cache.
  	 */
  	rcu_barrier();
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
99
  	kmem_cache_destroy(efs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  static int efs_remount(struct super_block *sb, int *flags, char *data)
  {
02b9984d6   Theodore Ts'o   fs: push sync_fil...
103
  	sync_filesystem(sb);
1751e8a6c   Linus Torvalds   Rename superblock...
104
  	*flags |= SB_RDONLY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
107
  static const struct super_operations efs_superblock_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  	.alloc_inode	= efs_alloc_inode,
f415c5112   Al Viro   efs: switch to ->...
109
  	.free_inode	= efs_free_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
  	.statfs		= efs_statfs,
  	.remount_fs	= efs_remount,
  };
396551644   Christoph Hellwig   exportfs: make st...
113
  static const struct export_operations efs_export_ops = {
05da08048   Christoph Hellwig   efs: new export ops
114
115
  	.fh_to_dentry	= efs_fh_to_dentry,
  	.fh_to_parent	= efs_fh_to_parent,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
119
120
  	.get_parent	= efs_get_parent,
  };
  
  static int __init init_efs_fs(void) {
  	int err;
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
121
122
  	pr_info(EFS_VERSION" - http://aeschi.ch.eu.org/efs/
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
  	err = init_inodecache();
  	if (err)
  		goto out1;
  	err = register_filesystem(&efs_fs_type);
  	if (err)
  		goto out;
  	return 0;
  out:
  	destroy_inodecache();
  out1:
  	return err;
  }
  
  static void __exit exit_efs_fs(void) {
  	unregister_filesystem(&efs_fs_type);
  	destroy_inodecache();
  }
  
  module_init(init_efs_fs)
  module_exit(exit_efs_fs)
  
  static efs_block_t efs_validate_vh(struct volume_header *vh) {
  	int		i;
  	__be32		cs, *ui;
  	int		csum;
  	efs_block_t	sblock = 0; /* shuts up gcc */
  	struct pt_types	*pt_entry;
  	int		pt_type, slice = -1;
  
  	if (be32_to_cpu(vh->vh_magic) != VHMAGIC) {
  		/*
  		 * assume that we're dealing with a partition and allow
  		 * read_super() to try and detect a valid superblock
  		 * on the next block.
  		 */
  		return 0;
  	}
  
  	ui = ((__be32 *) (vh + 1)) - 1;
  	for(csum = 0; ui >= ((__be32 *) vh);) {
  		cs = *ui--;
  		csum += be32_to_cpu(cs);
  	}
  	if (csum) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
167
168
  		pr_warn("SGI disklabel: checksum bad, label corrupted
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
  		return 0;
  	}
  
  #ifdef DEBUG
d1826f2a3   Fabian Frederick   fs/efs: convert p...
173
174
  	pr_debug("bf: \"%16s\"
  ", vh->vh_bootfile);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
182
183
184
185
  
  	for(i = 0; i < NVDIR; i++) {
  		int	j;
  		char	name[VDNAMESIZE+1];
  
  		for(j = 0; j < VDNAMESIZE; j++) {
  			name[j] = vh->vh_vd[i].vd_name[j];
  		}
  		name[j] = (char) 0;
  
  		if (name[0]) {
d1826f2a3   Fabian Frederick   fs/efs: convert p...
186
187
188
  			pr_debug("vh: %8s block: 0x%08x size: 0x%08x
  ",
  				name, (int) be32_to_cpu(vh->vh_vd[i].vd_lbn),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
195
196
197
198
199
200
  				(int) be32_to_cpu(vh->vh_vd[i].vd_nbytes));
  		}
  	}
  #endif
  
  	for(i = 0; i < NPARTAB; i++) {
  		pt_type = (int) be32_to_cpu(vh->vh_pt[i].pt_type);
  		for(pt_entry = sgi_pt_types; pt_entry->pt_name; pt_entry++) {
  			if (pt_type == pt_entry->pt_type) break;
  		}
  #ifdef DEBUG
  		if (be32_to_cpu(vh->vh_pt[i].pt_nblks)) {
d1826f2a3   Fabian Frederick   fs/efs: convert p...
201
202
203
204
205
206
  			pr_debug("pt %2d: start: %08d size: %08d type: 0x%02x (%s)
  ",
  				 i, (int)be32_to_cpu(vh->vh_pt[i].pt_firstlbn),
  				 (int)be32_to_cpu(vh->vh_pt[i].pt_nblks),
  				 pt_type, (pt_entry->pt_name) ?
  				 pt_entry->pt_name : "unknown");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
214
215
  		}
  #endif
  		if (IS_EFS(pt_type)) {
  			sblock = be32_to_cpu(vh->vh_pt[i].pt_firstlbn);
  			slice = i;
  		}
  	}
  
  	if (slice == -1) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
216
217
  		pr_notice("partition table contained no EFS partitions
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  #ifdef DEBUG
  	} else {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
220
221
  		pr_info("using slice %d (type %s, offset 0x%x)
  ", slice,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
  			(pt_entry->pt_name) ? pt_entry->pt_name : "unknown",
  			sblock);
  #endif
  	}
014c2544e   Jesper Juhl   return statement ...
226
  	return sblock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
  }
  
  static int efs_validate_super(struct efs_sb_info *sb, struct efs_super *super) {
014c2544e   Jesper Juhl   return statement ...
230
231
  	if (!IS_EFS_MAGIC(be32_to_cpu(super->fs_magic)))
  		return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
  
  	sb->fs_magic     = be32_to_cpu(super->fs_magic);
  	sb->total_blocks = be32_to_cpu(super->fs_size);
  	sb->first_block  = be32_to_cpu(super->fs_firstcg);
  	sb->group_size   = be32_to_cpu(super->fs_cgfsize);
  	sb->data_free    = be32_to_cpu(super->fs_tfree);
  	sb->inode_free   = be32_to_cpu(super->fs_tinode);
  	sb->inode_blocks = be16_to_cpu(super->fs_cgisize);
  	sb->total_groups = be16_to_cpu(super->fs_ncg);
      
  	return 0;    
  }
  
  static int efs_fill_super(struct super_block *s, void *d, int silent)
  {
  	struct efs_sb_info *sb;
  	struct buffer_head *bh;
  	struct inode *root;
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
250
   	sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
252
253
  	if (!sb)
  		return -ENOMEM;
  	s->s_fs_info = sb;
22b139691   Deepa Dinamani   fs: Fill in max a...
254
255
  	s->s_time_min = 0;
  	s->s_time_max = U32_MAX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
   
  	s->s_magic		= EFS_SUPER_MAGIC;
  	if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
259
260
  		pr_err("device does not support %d byte blocks
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  			EFS_BLOCKSIZE);
5a9ed6f5e   Al Viro   efs: get rid of -...
262
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
267
268
  	}
    
  	/* read the vh (volume header) block */
  	bh = sb_bread(s, 0);
  
  	if (!bh) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
269
270
  		pr_err("cannot read volume header
  ");
4108124f5   Heloise   fs/efs/super.c: f...
271
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
273
274
275
276
277
278
279
280
281
282
  	}
  
  	/*
  	 * if this returns zero then we didn't find any partition table.
  	 * this isn't (yet) an error - just assume for the moment that
  	 * the device is valid and go on to search for a superblock.
  	 */
  	sb->fs_start = efs_validate_vh((struct volume_header *) bh->b_data);
  	brelse(bh);
  
  	if (sb->fs_start == -1) {
5a9ed6f5e   Al Viro   efs: get rid of -...
283
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
  	}
  
  	bh = sb_bread(s, sb->fs_start + EFS_SUPER);
  	if (!bh) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
288
289
  		pr_err("cannot read superblock
  ");
4108124f5   Heloise   fs/efs/super.c: f...
290
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
  	}
  		
  	if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) {
  #ifdef DEBUG
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
295
296
297
  		pr_warn("invalid superblock at block %u
  ",
  			sb->fs_start + EFS_SUPER);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  #endif
  		brelse(bh);
5a9ed6f5e   Al Viro   efs: get rid of -...
300
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
  	}
  	brelse(bh);
bc98a42c1   David Howells   VFS: Convert sb->...
303
  	if (!sb_rdonly(s)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  #ifdef DEBUG
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
305
306
  		pr_info("forcing read-only mode
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  #endif
1751e8a6c   Linus Torvalds   Rename superblock...
308
  		s->s_flags |= SB_RDONLY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
  	}
  	s->s_op   = &efs_superblock_operations;
  	s->s_export_op = &efs_export_ops;
298384cd7   David Howells   iget: stop EFS fr...
312
313
  	root = efs_iget(s, EFS_ROOTINODE);
  	if (IS_ERR(root)) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
314
315
  		pr_err("get root inode failed
  ");
5a9ed6f5e   Al Viro   efs: get rid of -...
316
  		return PTR_ERR(root);
298384cd7   David Howells   iget: stop EFS fr...
317
  	}
48fde701a   Al Viro   switch open-coded...
318
  	s->s_root = d_make_root(root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	if (!(s->s_root)) {
f403d1dba   Fabian Frederick   fs/efs: add pr_fm...
320
321
  		pr_err("get root dentry failed
  ");
5a9ed6f5e   Al Viro   efs: get rid of -...
322
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
324
325
  	}
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  }
726c33422   David Howells   [PATCH] VFS: Perm...
327
  static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
514c91a9c   Coly Li   fs/efs: return f_...
328
329
330
  	struct super_block *sb = dentry->d_sb;
  	struct efs_sb_info *sbi = SUPER_INFO(sb);
  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
  
  	buf->f_type    = EFS_SUPER_MAGIC;	/* efs magic number */
  	buf->f_bsize   = EFS_BLOCKSIZE;		/* blocksize */
514c91a9c   Coly Li   fs/efs: return f_...
334
335
336
337
338
339
  	buf->f_blocks  = sbi->total_groups *	/* total data blocks */
  			(sbi->group_size - sbi->inode_blocks);
  	buf->f_bfree   = sbi->data_free;	/* free data blocks */
  	buf->f_bavail  = sbi->data_free;	/* free blocks for non-root */
  	buf->f_files   = sbi->total_groups *	/* total inodes */
  			sbi->inode_blocks *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
  			(EFS_BLOCKSIZE / sizeof(struct efs_dinode));
514c91a9c   Coly Li   fs/efs: return f_...
341
  	buf->f_ffree   = sbi->inode_free;	/* free inodes */
6d1349c76   Al Viro   [PATCH] reduce bo...
342
  	buf->f_fsid    = u64_to_fsid(id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
344
345
346
  	buf->f_namelen = EFS_MAXNAMELEN;	/* max filename length */
  
  	return 0;
  }