xref: /openbmc/linux/fs/isofs/inode.c (revision 9769f4eb3fad2dd53a5d24c81ee5f7f05450742b)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  linux/fs/isofs/inode.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  (C) 1991  Linus Torvalds - minix filesystem
51da177e4SLinus Torvalds  *      1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
61da177e4SLinus Torvalds  *      1994  Eberhard Moenkeberg - multi session handling.
71da177e4SLinus Torvalds  *      1995  Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs.
81da177e4SLinus Torvalds  *	1997  Gordon Chaffee - Joliet CDs
91da177e4SLinus Torvalds  *	1998  Eric Lammerts - ISO 9660 Level 3
101da177e4SLinus Torvalds  *	2004  Paul Serice - Inode Support pushed out from 4GB to 128GB
111da177e4SLinus Torvalds  *	2004  Paul Serice - NFS Export Operations
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/config.h>
1594f2f715SAl Viro #include <linux/init.h>
161da177e4SLinus Torvalds #include <linux/module.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/slab.h>
191da177e4SLinus Torvalds #include <linux/nls.h>
201da177e4SLinus Torvalds #include <linux/ctype.h>
211da177e4SLinus Torvalds #include <linux/smp_lock.h>
2294f2f715SAl Viro #include <linux/statfs.h>
2394f2f715SAl Viro #include <linux/cdrom.h>
241da177e4SLinus Torvalds #include <linux/parser.h>
251da177e4SLinus Torvalds 
2694f2f715SAl Viro #include "isofs.h"
271da177e4SLinus Torvalds #include "zisofs.h"
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #define BEQUIET
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
321da177e4SLinus Torvalds static int isofs_hash(struct dentry *parent, struct qstr *qstr);
331da177e4SLinus Torvalds static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
341da177e4SLinus Torvalds static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
371da177e4SLinus Torvalds static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr);
381da177e4SLinus Torvalds static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr);
391da177e4SLinus Torvalds static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
401da177e4SLinus Torvalds static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
411da177e4SLinus Torvalds #endif
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds static void isofs_put_super(struct super_block *sb)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds 	struct isofs_sb_info *sbi = ISOFS_SB(sb);
461da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
471da177e4SLinus Torvalds 	if (sbi->s_nls_iocharset) {
481da177e4SLinus Torvalds 		unload_nls(sbi->s_nls_iocharset);
491da177e4SLinus Torvalds 		sbi->s_nls_iocharset = NULL;
501da177e4SLinus Torvalds 	}
511da177e4SLinus Torvalds #endif
521da177e4SLinus Torvalds 
531da177e4SLinus Torvalds 	kfree(sbi);
541da177e4SLinus Torvalds 	sb->s_fs_info = NULL;
551da177e4SLinus Torvalds 	return;
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds static void isofs_read_inode(struct inode *);
591da177e4SLinus Torvalds static int isofs_statfs (struct super_block *, struct kstatfs *);
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds static kmem_cache_t *isofs_inode_cachep;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds static struct inode *isofs_alloc_inode(struct super_block *sb)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	struct iso_inode_info *ei;
669eb7f2c6SAndrew Morton 	ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL);
671da177e4SLinus Torvalds 	if (!ei)
681da177e4SLinus Torvalds 		return NULL;
691da177e4SLinus Torvalds 	return &ei->vfs_inode;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds static void isofs_destroy_inode(struct inode *inode)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds 	kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
781da177e4SLinus Torvalds {
799eb7f2c6SAndrew Morton 	struct iso_inode_info *ei = foo;
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
821da177e4SLinus Torvalds 	    SLAB_CTOR_CONSTRUCTOR)
831da177e4SLinus Torvalds 		inode_init_once(&ei->vfs_inode);
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds static int init_inodecache(void)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds 	isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
891da177e4SLinus Torvalds 					     sizeof(struct iso_inode_info),
901da177e4SLinus Torvalds 					     0, SLAB_RECLAIM_ACCOUNT,
911da177e4SLinus Torvalds 					     init_once, NULL);
921da177e4SLinus Torvalds 	if (isofs_inode_cachep == NULL)
931da177e4SLinus Torvalds 		return -ENOMEM;
941da177e4SLinus Torvalds 	return 0;
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds static void destroy_inodecache(void)
981da177e4SLinus Torvalds {
991da177e4SLinus Torvalds 	if (kmem_cache_destroy(isofs_inode_cachep))
1009eb7f2c6SAndrew Morton 		printk(KERN_INFO "iso_inode_cache: not all structures were "
1019eb7f2c6SAndrew Morton 					"freed\n");
1021da177e4SLinus Torvalds }
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds static int isofs_remount(struct super_block *sb, int *flags, char *data)
1051da177e4SLinus Torvalds {
1061da177e4SLinus Torvalds 	/* we probably want a lot more here */
1071da177e4SLinus Torvalds 	*flags |= MS_RDONLY;
1081da177e4SLinus Torvalds 	return 0;
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds static struct super_operations isofs_sops = {
1121da177e4SLinus Torvalds 	.alloc_inode	= isofs_alloc_inode,
1131da177e4SLinus Torvalds 	.destroy_inode	= isofs_destroy_inode,
1141da177e4SLinus Torvalds 	.read_inode	= isofs_read_inode,
1151da177e4SLinus Torvalds 	.put_super	= isofs_put_super,
1161da177e4SLinus Torvalds 	.statfs		= isofs_statfs,
1171da177e4SLinus Torvalds 	.remount_fs	= isofs_remount,
1181da177e4SLinus Torvalds };
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds static struct dentry_operations isofs_dentry_ops[] = {
1221da177e4SLinus Torvalds 	{
1231da177e4SLinus Torvalds 		.d_hash		= isofs_hash,
1241da177e4SLinus Torvalds 		.d_compare	= isofs_dentry_cmp,
1251da177e4SLinus Torvalds 	},
1261da177e4SLinus Torvalds 	{
1271da177e4SLinus Torvalds 		.d_hash		= isofs_hashi,
1281da177e4SLinus Torvalds 		.d_compare	= isofs_dentry_cmpi,
1291da177e4SLinus Torvalds 	},
1301da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
1311da177e4SLinus Torvalds 	{
1321da177e4SLinus Torvalds 		.d_hash		= isofs_hash_ms,
1331da177e4SLinus Torvalds 		.d_compare	= isofs_dentry_cmp_ms,
1341da177e4SLinus Torvalds 	},
1351da177e4SLinus Torvalds 	{
1361da177e4SLinus Torvalds 		.d_hash		= isofs_hashi_ms,
1371da177e4SLinus Torvalds 		.d_compare	= isofs_dentry_cmpi_ms,
1389eb7f2c6SAndrew Morton 	},
1391da177e4SLinus Torvalds #endif
1401da177e4SLinus Torvalds };
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds struct iso9660_options{
1431da177e4SLinus Torvalds 	char map;
1441da177e4SLinus Torvalds 	char rock;
1451da177e4SLinus Torvalds 	char joliet;
1461da177e4SLinus Torvalds 	char cruft;
147*9769f4ebSJeremy White 	char hide;
148*9769f4ebSJeremy White 	char showassoc;
1491da177e4SLinus Torvalds 	char nocompress;
1501da177e4SLinus Torvalds 	unsigned char check;
1511da177e4SLinus Torvalds 	unsigned int blocksize;
1521da177e4SLinus Torvalds 	mode_t mode;
1531da177e4SLinus Torvalds 	gid_t gid;
1541da177e4SLinus Torvalds 	uid_t uid;
1551da177e4SLinus Torvalds 	char *iocharset;
1561da177e4SLinus Torvalds 	unsigned char utf8;
1571da177e4SLinus Torvalds         /* LVE */
1581da177e4SLinus Torvalds         s32 session;
1591da177e4SLinus Torvalds         s32 sbsector;
1601da177e4SLinus Torvalds };
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds /*
1631da177e4SLinus Torvalds  * Compute the hash for the isofs name corresponding to the dentry.
1641da177e4SLinus Torvalds  */
1651da177e4SLinus Torvalds static int
1661da177e4SLinus Torvalds isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms)
1671da177e4SLinus Torvalds {
1681da177e4SLinus Torvalds 	const char *name;
1691da177e4SLinus Torvalds 	int len;
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds 	len = qstr->len;
1721da177e4SLinus Torvalds 	name = qstr->name;
1731da177e4SLinus Torvalds 	if (ms) {
1741da177e4SLinus Torvalds 		while (len && name[len-1] == '.')
1751da177e4SLinus Torvalds 			len--;
1761da177e4SLinus Torvalds 	}
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 	qstr->hash = full_name_hash(name, len);
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 	return 0;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds /*
1841da177e4SLinus Torvalds  * Compute the hash for the isofs name corresponding to the dentry.
1851da177e4SLinus Torvalds  */
1861da177e4SLinus Torvalds static int
1871da177e4SLinus Torvalds isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
1881da177e4SLinus Torvalds {
1891da177e4SLinus Torvalds 	const char *name;
1901da177e4SLinus Torvalds 	int len;
1911da177e4SLinus Torvalds 	char c;
1921da177e4SLinus Torvalds 	unsigned long hash;
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	len = qstr->len;
1951da177e4SLinus Torvalds 	name = qstr->name;
1961da177e4SLinus Torvalds 	if (ms) {
1971da177e4SLinus Torvalds 		while (len && name[len-1] == '.')
1981da177e4SLinus Torvalds 			len--;
1991da177e4SLinus Torvalds 	}
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	hash = init_name_hash();
2021da177e4SLinus Torvalds 	while (len--) {
2031da177e4SLinus Torvalds 		c = tolower(*name++);
2041da177e4SLinus Torvalds 		hash = partial_name_hash(tolower(c), hash);
2051da177e4SLinus Torvalds 	}
2061da177e4SLinus Torvalds 	qstr->hash = end_name_hash(hash);
2071da177e4SLinus Torvalds 
2081da177e4SLinus Torvalds 	return 0;
2091da177e4SLinus Torvalds }
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds /*
2121da177e4SLinus Torvalds  * Case insensitive compare of two isofs names.
2131da177e4SLinus Torvalds  */
2149eb7f2c6SAndrew Morton static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a,
2159eb7f2c6SAndrew Morton 				struct qstr *b, int ms)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	int alen, blen;
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	/* A filename cannot end in '.' or we treat it like it has none */
2201da177e4SLinus Torvalds 	alen = a->len;
2211da177e4SLinus Torvalds 	blen = b->len;
2221da177e4SLinus Torvalds 	if (ms) {
2231da177e4SLinus Torvalds 		while (alen && a->name[alen-1] == '.')
2241da177e4SLinus Torvalds 			alen--;
2251da177e4SLinus Torvalds 		while (blen && b->name[blen-1] == '.')
2261da177e4SLinus Torvalds 			blen--;
2271da177e4SLinus Torvalds 	}
2281da177e4SLinus Torvalds 	if (alen == blen) {
2291da177e4SLinus Torvalds 		if (strnicmp(a->name, b->name, alen) == 0)
2301da177e4SLinus Torvalds 			return 0;
2311da177e4SLinus Torvalds 	}
2321da177e4SLinus Torvalds 	return 1;
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds /*
2361da177e4SLinus Torvalds  * Case sensitive compare of two isofs names.
2371da177e4SLinus Torvalds  */
2389eb7f2c6SAndrew Morton static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a,
2399eb7f2c6SAndrew Morton 					struct qstr *b, int ms)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds 	int alen, blen;
2421da177e4SLinus Torvalds 
2431da177e4SLinus Torvalds 	/* A filename cannot end in '.' or we treat it like it has none */
2441da177e4SLinus Torvalds 	alen = a->len;
2451da177e4SLinus Torvalds 	blen = b->len;
2461da177e4SLinus Torvalds 	if (ms) {
2471da177e4SLinus Torvalds 		while (alen && a->name[alen-1] == '.')
2481da177e4SLinus Torvalds 			alen--;
2491da177e4SLinus Torvalds 		while (blen && b->name[blen-1] == '.')
2501da177e4SLinus Torvalds 			blen--;
2511da177e4SLinus Torvalds 	}
2521da177e4SLinus Torvalds 	if (alen == blen) {
2531da177e4SLinus Torvalds 		if (strncmp(a->name, b->name, alen) == 0)
2541da177e4SLinus Torvalds 			return 0;
2551da177e4SLinus Torvalds 	}
2561da177e4SLinus Torvalds 	return 1;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds static int
2601da177e4SLinus Torvalds isofs_hash(struct dentry *dentry, struct qstr *qstr)
2611da177e4SLinus Torvalds {
2621da177e4SLinus Torvalds 	return isofs_hash_common(dentry, qstr, 0);
2631da177e4SLinus Torvalds }
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds static int
2661da177e4SLinus Torvalds isofs_hashi(struct dentry *dentry, struct qstr *qstr)
2671da177e4SLinus Torvalds {
2681da177e4SLinus Torvalds 	return isofs_hashi_common(dentry, qstr, 0);
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds static int
2721da177e4SLinus Torvalds isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds 	return isofs_dentry_cmp_common(dentry, a, b, 0);
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds 
2771da177e4SLinus Torvalds static int
2781da177e4SLinus Torvalds isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b)
2791da177e4SLinus Torvalds {
2801da177e4SLinus Torvalds 	return isofs_dentry_cmpi_common(dentry, a, b, 0);
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
2841da177e4SLinus Torvalds static int
2851da177e4SLinus Torvalds isofs_hash_ms(struct dentry *dentry, struct qstr *qstr)
2861da177e4SLinus Torvalds {
2871da177e4SLinus Torvalds 	return isofs_hash_common(dentry, qstr, 1);
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds static int
2911da177e4SLinus Torvalds isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
2921da177e4SLinus Torvalds {
2931da177e4SLinus Torvalds 	return isofs_hashi_common(dentry, qstr, 1);
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds static int
2971da177e4SLinus Torvalds isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
2981da177e4SLinus Torvalds {
2991da177e4SLinus Torvalds 	return isofs_dentry_cmp_common(dentry, a, b, 1);
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds static int
3031da177e4SLinus Torvalds isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
3041da177e4SLinus Torvalds {
3051da177e4SLinus Torvalds 	return isofs_dentry_cmpi_common(dentry, a, b, 1);
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds #endif
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds enum {
3101da177e4SLinus Torvalds 	Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
3111da177e4SLinus Torvalds 	Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
3121da177e4SLinus Torvalds 	Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
313*9769f4ebSJeremy White 	Opt_nocompress, Opt_hide, Opt_showassoc,
3141da177e4SLinus Torvalds };
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds static match_table_t tokens = {
3171da177e4SLinus Torvalds 	{Opt_norock, "norock"},
3181da177e4SLinus Torvalds 	{Opt_nojoliet, "nojoliet"},
3191da177e4SLinus Torvalds 	{Opt_unhide, "unhide"},
320*9769f4ebSJeremy White 	{Opt_hide, "hide"},
321*9769f4ebSJeremy White 	{Opt_showassoc, "showassoc"},
3221da177e4SLinus Torvalds 	{Opt_cruft, "cruft"},
3231da177e4SLinus Torvalds 	{Opt_utf8, "utf8"},
3241da177e4SLinus Torvalds 	{Opt_iocharset, "iocharset=%s"},
3251da177e4SLinus Torvalds 	{Opt_map_a, "map=acorn"},
3261da177e4SLinus Torvalds 	{Opt_map_a, "map=a"},
3271da177e4SLinus Torvalds 	{Opt_map_n, "map=normal"},
3281da177e4SLinus Torvalds 	{Opt_map_n, "map=n"},
3291da177e4SLinus Torvalds 	{Opt_map_o, "map=off"},
3301da177e4SLinus Torvalds 	{Opt_map_o, "map=o"},
3311da177e4SLinus Torvalds 	{Opt_session, "session=%u"},
3321da177e4SLinus Torvalds 	{Opt_sb, "sbsector=%u"},
3331da177e4SLinus Torvalds 	{Opt_check_r, "check=relaxed"},
3341da177e4SLinus Torvalds 	{Opt_check_r, "check=r"},
3351da177e4SLinus Torvalds 	{Opt_check_s, "check=strict"},
3361da177e4SLinus Torvalds 	{Opt_check_s, "check=s"},
3371da177e4SLinus Torvalds 	{Opt_uid, "uid=%u"},
3381da177e4SLinus Torvalds 	{Opt_gid, "gid=%u"},
3391da177e4SLinus Torvalds 	{Opt_mode, "mode=%u"},
3401da177e4SLinus Torvalds 	{Opt_block, "block=%u"},
3411da177e4SLinus Torvalds 	{Opt_ignore, "conv=binary"},
3421da177e4SLinus Torvalds 	{Opt_ignore, "conv=b"},
3431da177e4SLinus Torvalds 	{Opt_ignore, "conv=text"},
3441da177e4SLinus Torvalds 	{Opt_ignore, "conv=t"},
3451da177e4SLinus Torvalds 	{Opt_ignore, "conv=mtext"},
3461da177e4SLinus Torvalds 	{Opt_ignore, "conv=m"},
3471da177e4SLinus Torvalds 	{Opt_ignore, "conv=auto"},
3481da177e4SLinus Torvalds 	{Opt_ignore, "conv=a"},
3491da177e4SLinus Torvalds 	{Opt_nocompress, "nocompress"},
3501da177e4SLinus Torvalds 	{Opt_err, NULL}
3511da177e4SLinus Torvalds };
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds static int parse_options(char *options, struct iso9660_options *popt)
3541da177e4SLinus Torvalds {
3551da177e4SLinus Torvalds 	char *p;
3561da177e4SLinus Torvalds 	int option;
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds 	popt->map = 'n';
3591da177e4SLinus Torvalds 	popt->rock = 'y';
3601da177e4SLinus Torvalds 	popt->joliet = 'y';
3611da177e4SLinus Torvalds 	popt->cruft = 'n';
362*9769f4ebSJeremy White 	popt->hide = 'n';
363*9769f4ebSJeremy White 	popt->showassoc = 'n';
3641da177e4SLinus Torvalds 	popt->check = 'u';		/* unset */
3651da177e4SLinus Torvalds 	popt->nocompress = 0;
3661da177e4SLinus Torvalds 	popt->blocksize = 1024;
3671da177e4SLinus Torvalds 	popt->mode = S_IRUGO | S_IXUGO; /* r-x for all.  The disc could
3681da177e4SLinus Torvalds 					   be shared with DOS machines so
3691da177e4SLinus Torvalds 					   virtually anything could be
3701da177e4SLinus Torvalds 					   a valid executable. */
3711da177e4SLinus Torvalds 	popt->gid = 0;
3721da177e4SLinus Torvalds 	popt->uid = 0;
3731da177e4SLinus Torvalds 	popt->iocharset = NULL;
3741da177e4SLinus Torvalds 	popt->utf8 = 0;
3751da177e4SLinus Torvalds 	popt->session=-1;
3761da177e4SLinus Torvalds 	popt->sbsector=-1;
3771da177e4SLinus Torvalds 	if (!options)
3781da177e4SLinus Torvalds 		return 1;
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	while ((p = strsep(&options, ",")) != NULL) {
3811da177e4SLinus Torvalds 		int token;
3821da177e4SLinus Torvalds 		substring_t args[MAX_OPT_ARGS];
3831da177e4SLinus Torvalds 		unsigned n;
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 		if (!*p)
3861da177e4SLinus Torvalds 			continue;
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 		token = match_token(p, tokens, args);
3891da177e4SLinus Torvalds 		switch (token) {
3901da177e4SLinus Torvalds 		case Opt_norock:
3911da177e4SLinus Torvalds 			popt->rock = 'n';
3921da177e4SLinus Torvalds 			break;
3931da177e4SLinus Torvalds 		case Opt_nojoliet:
3941da177e4SLinus Torvalds 			popt->joliet = 'n';
3951da177e4SLinus Torvalds 			break;
396*9769f4ebSJeremy White 		case Opt_hide:
397*9769f4ebSJeremy White 			popt->hide = 'y';
398*9769f4ebSJeremy White 			break;
3991da177e4SLinus Torvalds 		case Opt_unhide:
400*9769f4ebSJeremy White 		case Opt_showassoc:
401*9769f4ebSJeremy White 			popt->showassoc = 'y';
4021da177e4SLinus Torvalds 			break;
4031da177e4SLinus Torvalds 		case Opt_cruft:
4041da177e4SLinus Torvalds 			popt->cruft = 'y';
4051da177e4SLinus Torvalds 			break;
4061da177e4SLinus Torvalds 		case Opt_utf8:
4071da177e4SLinus Torvalds 			popt->utf8 = 1;
4081da177e4SLinus Torvalds 			break;
4091da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
4101da177e4SLinus Torvalds 		case Opt_iocharset:
4111da177e4SLinus Torvalds 			popt->iocharset = match_strdup(&args[0]);
4121da177e4SLinus Torvalds 			break;
4131da177e4SLinus Torvalds #endif
4141da177e4SLinus Torvalds 		case Opt_map_a:
4151da177e4SLinus Torvalds 			popt->map = 'a';
4161da177e4SLinus Torvalds 			break;
4171da177e4SLinus Torvalds 		case Opt_map_o:
4181da177e4SLinus Torvalds 			popt->map = 'o';
4191da177e4SLinus Torvalds 			break;
4201da177e4SLinus Torvalds 		case Opt_map_n:
4211da177e4SLinus Torvalds 			popt->map = 'n';
4221da177e4SLinus Torvalds 			break;
4231da177e4SLinus Torvalds 		case Opt_session:
4241da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
4251da177e4SLinus Torvalds 				return 0;
4261da177e4SLinus Torvalds 			n = option;
4271da177e4SLinus Torvalds 			if (n > 99)
4281da177e4SLinus Torvalds 				return 0;
4291da177e4SLinus Torvalds 			popt->session = n + 1;
4301da177e4SLinus Torvalds 			break;
4311da177e4SLinus Torvalds 		case Opt_sb:
4321da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
4331da177e4SLinus Torvalds 				return 0;
4341da177e4SLinus Torvalds 			popt->sbsector = option;
4351da177e4SLinus Torvalds 			break;
4361da177e4SLinus Torvalds 		case Opt_check_r:
4371da177e4SLinus Torvalds 			popt->check = 'r';
4381da177e4SLinus Torvalds 			break;
4391da177e4SLinus Torvalds 		case Opt_check_s:
4401da177e4SLinus Torvalds 			popt->check = 's';
4411da177e4SLinus Torvalds 			break;
4421da177e4SLinus Torvalds 		case Opt_ignore:
4431da177e4SLinus Torvalds 			break;
4441da177e4SLinus Torvalds 		case Opt_uid:
4451da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
4461da177e4SLinus Torvalds 				return 0;
4471da177e4SLinus Torvalds 			popt->uid = option;
4481da177e4SLinus Torvalds 			break;
4491da177e4SLinus Torvalds 		case Opt_gid:
4501da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
4511da177e4SLinus Torvalds 				return 0;
4521da177e4SLinus Torvalds 			popt->gid = option;
4531da177e4SLinus Torvalds 			break;
4541da177e4SLinus Torvalds 		case Opt_mode:
4551da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
4561da177e4SLinus Torvalds 				return 0;
4571da177e4SLinus Torvalds 			popt->mode = option;
4581da177e4SLinus Torvalds 			break;
4591da177e4SLinus Torvalds 		case Opt_block:
4601da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
4611da177e4SLinus Torvalds 				return 0;
4621da177e4SLinus Torvalds 			n = option;
4631da177e4SLinus Torvalds 			if (n != 512 && n != 1024 && n != 2048)
4641da177e4SLinus Torvalds 				return 0;
4651da177e4SLinus Torvalds 			popt->blocksize = n;
4661da177e4SLinus Torvalds 			break;
4671da177e4SLinus Torvalds 		case Opt_nocompress:
4681da177e4SLinus Torvalds 			popt->nocompress = 1;
4691da177e4SLinus Torvalds 			break;
4701da177e4SLinus Torvalds 		default:
4711da177e4SLinus Torvalds 			return 0;
4721da177e4SLinus Torvalds 		}
4731da177e4SLinus Torvalds 	}
4741da177e4SLinus Torvalds 	return 1;
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds /*
4781da177e4SLinus Torvalds  * look if the driver can tell the multi session redirection value
4791da177e4SLinus Torvalds  *
4801da177e4SLinus Torvalds  * don't change this if you don't know what you do, please!
4811da177e4SLinus Torvalds  * Multisession is legal only with XA disks.
4821da177e4SLinus Torvalds  * A non-XA disk with more than one volume descriptor may do it right, but
4831da177e4SLinus Torvalds  * usually is written in a nowhere standardized "multi-partition" manner.
4841da177e4SLinus Torvalds  * Multisession uses absolute addressing (solely the first frame of the whole
4851da177e4SLinus Torvalds  * track is #0), multi-partition uses relative addressing (each first frame of
4861da177e4SLinus Torvalds  * each track is #0), and a track is not a session.
4871da177e4SLinus Torvalds  *
4881da177e4SLinus Torvalds  * A broken CDwriter software or drive firmware does not set new standards,
4891da177e4SLinus Torvalds  * at least not if conflicting with the existing ones.
4901da177e4SLinus Torvalds  *
4911da177e4SLinus Torvalds  * emoenke@gwdg.de
4921da177e4SLinus Torvalds  */
4931da177e4SLinus Torvalds #define WE_OBEY_THE_WRITTEN_STANDARDS 1
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
4961da177e4SLinus Torvalds {
4971da177e4SLinus Torvalds 	struct cdrom_multisession ms_info;
4981da177e4SLinus Torvalds 	unsigned int vol_desc_start;
4991da177e4SLinus Torvalds 	struct block_device *bdev = sb->s_bdev;
5001da177e4SLinus Torvalds 	int i;
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 	vol_desc_start=0;
5031da177e4SLinus Torvalds 	ms_info.addr_format=CDROM_LBA;
5041da177e4SLinus Torvalds 	if(session >= 0 && session <= 99) {
5051da177e4SLinus Torvalds 		struct cdrom_tocentry Te;
5061da177e4SLinus Torvalds 		Te.cdte_track=session;
5071da177e4SLinus Torvalds 		Te.cdte_format=CDROM_LBA;
5081da177e4SLinus Torvalds 		i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
5091da177e4SLinus Torvalds 		if (!i) {
5101da177e4SLinus Torvalds 			printk(KERN_DEBUG "Session %d start %d type %d\n",
5111da177e4SLinus Torvalds 			       session, Te.cdte_addr.lba,
5121da177e4SLinus Torvalds 			       Te.cdte_ctrl&CDROM_DATA_TRACK);
5131da177e4SLinus Torvalds 			if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
5141da177e4SLinus Torvalds 				return Te.cdte_addr.lba;
5151da177e4SLinus Torvalds 		}
5161da177e4SLinus Torvalds 
5171da177e4SLinus Torvalds 		printk(KERN_ERR "Invalid session number or type of track\n");
5181da177e4SLinus Torvalds 	}
5191da177e4SLinus Torvalds 	i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
5209eb7f2c6SAndrew Morton 	if (session > 0)
5219eb7f2c6SAndrew Morton 		printk(KERN_ERR "Invalid session number\n");
5221da177e4SLinus Torvalds #if 0
5231da177e4SLinus Torvalds 	printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
5241da177e4SLinus Torvalds 	if (i==0) {
5251da177e4SLinus Torvalds 		printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
5261da177e4SLinus Torvalds 		printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
5271da177e4SLinus Torvalds 	}
5281da177e4SLinus Torvalds #endif
5291da177e4SLinus Torvalds 	if (i==0)
5301da177e4SLinus Torvalds #if WE_OBEY_THE_WRITTEN_STANDARDS
5311da177e4SLinus Torvalds         if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
5321da177e4SLinus Torvalds #endif
5331da177e4SLinus Torvalds 		vol_desc_start=ms_info.addr.lba;
5341da177e4SLinus Torvalds 	return vol_desc_start;
5351da177e4SLinus Torvalds }
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds /*
5381da177e4SLinus Torvalds  * Initialize the superblock and read the root inode.
5391da177e4SLinus Torvalds  *
5401da177e4SLinus Torvalds  * Note: a check_disk_change() has been done immediately prior
5411da177e4SLinus Torvalds  * to this call, so we don't need to check again.
5421da177e4SLinus Torvalds  */
5431da177e4SLinus Torvalds static int isofs_fill_super(struct super_block *s, void *data, int silent)
5441da177e4SLinus Torvalds {
5451da177e4SLinus Torvalds 	struct buffer_head	      * bh = NULL, *pri_bh = NULL;
5461da177e4SLinus Torvalds 	struct hs_primary_descriptor  * h_pri = NULL;
5471da177e4SLinus Torvalds 	struct iso_primary_descriptor * pri = NULL;
5481da177e4SLinus Torvalds 	struct iso_supplementary_descriptor *sec = NULL;
5491da177e4SLinus Torvalds 	struct iso_directory_record   * rootp;
5501da177e4SLinus Torvalds 	int				joliet_level = 0;
5511da177e4SLinus Torvalds 	int				iso_blknum, block;
5521da177e4SLinus Torvalds 	int				orig_zonesize;
5531da177e4SLinus Torvalds 	int				table;
5541da177e4SLinus Torvalds 	unsigned int			vol_desc_start;
5551da177e4SLinus Torvalds 	unsigned long			first_data_zone;
5561da177e4SLinus Torvalds 	struct inode		      * inode;
5571da177e4SLinus Torvalds 	struct iso9660_options		opt;
5581da177e4SLinus Torvalds 	struct isofs_sb_info	      * sbi;
5591da177e4SLinus Torvalds 
5609eb7f2c6SAndrew Morton 	sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
5611da177e4SLinus Torvalds 	if (!sbi)
5621da177e4SLinus Torvalds 		return -ENOMEM;
5631da177e4SLinus Torvalds 	s->s_fs_info = sbi;
5649eb7f2c6SAndrew Morton 	memset(sbi, 0, sizeof(*sbi));
5651da177e4SLinus Torvalds 
5661da177e4SLinus Torvalds 	if (!parse_options((char *)data, &opt))
5671da177e4SLinus Torvalds 		goto out_freesbi;
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds 	/*
5701da177e4SLinus Torvalds 	 * First of all, get the hardware blocksize for this device.
5711da177e4SLinus Torvalds 	 * If we don't know what it is, or the hardware blocksize is
5721da177e4SLinus Torvalds 	 * larger than the blocksize the user specified, then use
5731da177e4SLinus Torvalds 	 * that value.
5741da177e4SLinus Torvalds 	 */
5751da177e4SLinus Torvalds 	/*
5761da177e4SLinus Torvalds 	 * What if bugger tells us to go beyond page size?
5771da177e4SLinus Torvalds 	 */
5781da177e4SLinus Torvalds 	opt.blocksize = sb_min_blocksize(s, opt.blocksize);
5791da177e4SLinus Torvalds 
5801da177e4SLinus Torvalds 	sbi->s_high_sierra = 0; /* default is iso9660 */
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds 	vol_desc_start = (opt.sbsector != -1) ?
5831da177e4SLinus Torvalds 		opt.sbsector : isofs_get_last_session(s,opt.session);
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds   	for (iso_blknum = vol_desc_start+16;
5861da177e4SLinus Torvalds              iso_blknum < vol_desc_start+100; iso_blknum++)
5871da177e4SLinus Torvalds 	{
5881da177e4SLinus Torvalds 	    struct hs_volume_descriptor   * hdp;
5891da177e4SLinus Torvalds 	    struct iso_volume_descriptor  * vdp;
5901da177e4SLinus Torvalds 
5911da177e4SLinus Torvalds 	    block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
5921da177e4SLinus Torvalds 	    if (!(bh = sb_bread(s, block)))
5931da177e4SLinus Torvalds 		goto out_no_read;
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 	    vdp = (struct iso_volume_descriptor *)bh->b_data;
5961da177e4SLinus Torvalds 	    hdp = (struct hs_volume_descriptor *)bh->b_data;
5971da177e4SLinus Torvalds 
5981da177e4SLinus Torvalds 	    /* Due to the overlapping physical location of the descriptors,
5991da177e4SLinus Torvalds 	     * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
6001da177e4SLinus Torvalds 	     * proper identification in this case, we first check for ISO.
6011da177e4SLinus Torvalds 	     */
6021da177e4SLinus Torvalds 	    if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
6031da177e4SLinus Torvalds 		if (isonum_711 (vdp->type) == ISO_VD_END)
6041da177e4SLinus Torvalds 		    break;
6051da177e4SLinus Torvalds 		if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
6061da177e4SLinus Torvalds 		    if (pri == NULL) {
6071da177e4SLinus Torvalds 			pri = (struct iso_primary_descriptor *)vdp;
6081da177e4SLinus Torvalds 			/* Save the buffer in case we need it ... */
6091da177e4SLinus Torvalds 			pri_bh = bh;
6101da177e4SLinus Torvalds 			bh = NULL;
6111da177e4SLinus Torvalds 		    }
6121da177e4SLinus Torvalds 		}
6131da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
6141da177e4SLinus Torvalds 		else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
6151da177e4SLinus Torvalds 		    sec = (struct iso_supplementary_descriptor *)vdp;
6161da177e4SLinus Torvalds 		    if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
6171da177e4SLinus Torvalds 			if (opt.joliet == 'y') {
6181da177e4SLinus Torvalds 			    if (sec->escape[2] == 0x40) {
6191da177e4SLinus Torvalds 				joliet_level = 1;
6201da177e4SLinus Torvalds 			    } else if (sec->escape[2] == 0x43) {
6211da177e4SLinus Torvalds 				joliet_level = 2;
6221da177e4SLinus Torvalds 			    } else if (sec->escape[2] == 0x45) {
6231da177e4SLinus Torvalds 				joliet_level = 3;
6241da177e4SLinus Torvalds 			    }
6251da177e4SLinus Torvalds 			    printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n",
6261da177e4SLinus Torvalds 				   joliet_level);
6271da177e4SLinus Torvalds 			}
6281da177e4SLinus Torvalds 			goto root_found;
6291da177e4SLinus Torvalds 		    } else {
6301da177e4SLinus Torvalds 			/* Unknown supplementary volume descriptor */
6311da177e4SLinus Torvalds 			sec = NULL;
6321da177e4SLinus Torvalds 		    }
6331da177e4SLinus Torvalds 		}
6341da177e4SLinus Torvalds #endif
6351da177e4SLinus Torvalds 	    } else {
6361da177e4SLinus Torvalds 	        if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
6371da177e4SLinus Torvalds 		    if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
6381da177e4SLinus Torvalds 		        goto out_freebh;
6391da177e4SLinus Torvalds 
6401da177e4SLinus Torvalds 		    sbi->s_high_sierra = 1;
6411da177e4SLinus Torvalds 		    opt.rock = 'n';
6421da177e4SLinus Torvalds 		    h_pri = (struct hs_primary_descriptor *)vdp;
6431da177e4SLinus Torvalds 		    goto root_found;
6441da177e4SLinus Torvalds 		}
6451da177e4SLinus Torvalds 	    }
6461da177e4SLinus Torvalds 
6471da177e4SLinus Torvalds             /* Just skip any volume descriptors we don't recognize */
6481da177e4SLinus Torvalds 
6491da177e4SLinus Torvalds 	    brelse(bh);
6501da177e4SLinus Torvalds 	    bh = NULL;
6511da177e4SLinus Torvalds 	}
6521da177e4SLinus Torvalds 	/*
6531da177e4SLinus Torvalds 	 * If we fall through, either no volume descriptor was found,
6541da177e4SLinus Torvalds 	 * or else we passed a primary descriptor looking for others.
6551da177e4SLinus Torvalds 	 */
6561da177e4SLinus Torvalds 	if (!pri)
6571da177e4SLinus Torvalds 		goto out_unknown_format;
6581da177e4SLinus Torvalds 	brelse(bh);
6591da177e4SLinus Torvalds 	bh = pri_bh;
6601da177e4SLinus Torvalds 	pri_bh = NULL;
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds root_found:
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	if (joliet_level && (pri == NULL || opt.rock == 'n')) {
6651da177e4SLinus Torvalds 	    /* This is the case of Joliet with the norock mount flag.
6661da177e4SLinus Torvalds 	     * A disc with both Joliet and Rock Ridge is handled later
6671da177e4SLinus Torvalds 	     */
6681da177e4SLinus Torvalds 	    pri = (struct iso_primary_descriptor *) sec;
6691da177e4SLinus Torvalds 	}
6701da177e4SLinus Torvalds 
6711da177e4SLinus Torvalds 	if(sbi->s_high_sierra){
6721da177e4SLinus Torvalds 	  rootp = (struct iso_directory_record *) h_pri->root_directory_record;
6731da177e4SLinus Torvalds 	  sbi->s_nzones = isonum_733 (h_pri->volume_space_size);
6741da177e4SLinus Torvalds 	  sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size);
6751da177e4SLinus Torvalds 	  sbi->s_max_size = isonum_733(h_pri->volume_space_size);
6761da177e4SLinus Torvalds 	} else {
6771da177e4SLinus Torvalds 	  if (!pri)
6781da177e4SLinus Torvalds 	    goto out_freebh;
6791da177e4SLinus Torvalds 	  rootp = (struct iso_directory_record *) pri->root_directory_record;
6801da177e4SLinus Torvalds 	  sbi->s_nzones = isonum_733 (pri->volume_space_size);
6811da177e4SLinus Torvalds 	  sbi->s_log_zone_size = isonum_723 (pri->logical_block_size);
6821da177e4SLinus Torvalds 	  sbi->s_max_size = isonum_733(pri->volume_space_size);
6831da177e4SLinus Torvalds 	}
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds 	sbi->s_ninodes = 0; /* No way to figure this out easily */
6861da177e4SLinus Torvalds 
6871da177e4SLinus Torvalds 	orig_zonesize = sbi->s_log_zone_size;
6881da177e4SLinus Torvalds 	/*
6891da177e4SLinus Torvalds 	 * If the zone size is smaller than the hardware sector size,
6901da177e4SLinus Torvalds 	 * this is a fatal error.  This would occur if the disc drive
6911da177e4SLinus Torvalds 	 * had sectors that were 2048 bytes, but the filesystem had
6921da177e4SLinus Torvalds 	 * blocks that were 512 bytes (which should only very rarely
6931da177e4SLinus Torvalds 	 * happen.)
6941da177e4SLinus Torvalds 	 */
6951da177e4SLinus Torvalds 	if(orig_zonesize < opt.blocksize)
6961da177e4SLinus Torvalds 		goto out_bad_size;
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	/* RDE: convert log zone size to bit shift */
6991da177e4SLinus Torvalds 	switch (sbi->s_log_zone_size)
7001da177e4SLinus Torvalds 	  { case  512: sbi->s_log_zone_size =  9; break;
7011da177e4SLinus Torvalds 	    case 1024: sbi->s_log_zone_size = 10; break;
7021da177e4SLinus Torvalds 	    case 2048: sbi->s_log_zone_size = 11; break;
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds 	    default:
7051da177e4SLinus Torvalds 		goto out_bad_zone_size;
7061da177e4SLinus Torvalds 	  }
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 	s->s_magic = ISOFS_SUPER_MAGIC;
7091da177e4SLinus Torvalds 	s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	/* The CDROM is read-only, has no nodes (devices) on it, and since
7121da177e4SLinus Torvalds 	   all of the files appear to be owned by root, we really do not want
7131da177e4SLinus Torvalds 	   to allow suid.  (suid or devices will not show up unless we have
7141da177e4SLinus Torvalds 	   Rock Ridge extensions) */
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	/* Set this for reference. Its not currently used except on write
7191da177e4SLinus Torvalds 	   which we don't have .. */
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds 	first_data_zone = isonum_733 (rootp->extent) +
7221da177e4SLinus Torvalds 			  isonum_711 (rootp->ext_attr_length);
7231da177e4SLinus Torvalds 	sbi->s_firstdatazone = first_data_zone;
7241da177e4SLinus Torvalds #ifndef BEQUIET
7251da177e4SLinus Torvalds 	printk(KERN_DEBUG "Max size:%ld   Log zone size:%ld\n",
7261da177e4SLinus Torvalds 	       sbi->s_max_size,
7271da177e4SLinus Torvalds 	       1UL << sbi->s_log_zone_size);
7281da177e4SLinus Torvalds 	printk(KERN_DEBUG "First datazone:%ld\n", sbi->s_firstdatazone);
7291da177e4SLinus Torvalds 	if(sbi->s_high_sierra)
7301da177e4SLinus Torvalds 		printk(KERN_DEBUG "Disc in High Sierra format.\n");
7311da177e4SLinus Torvalds #endif
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 	/*
7341da177e4SLinus Torvalds 	 * If the Joliet level is set, we _may_ decide to use the
7351da177e4SLinus Torvalds 	 * secondary descriptor, but can't be sure until after we
7361da177e4SLinus Torvalds 	 * read the root inode. But before reading the root inode
7371da177e4SLinus Torvalds 	 * we may need to change the device blocksize, and would
7381da177e4SLinus Torvalds 	 * rather release the old buffer first. So, we cache the
7391da177e4SLinus Torvalds 	 * first_data_zone value from the secondary descriptor.
7401da177e4SLinus Torvalds 	 */
7411da177e4SLinus Torvalds 	if (joliet_level) {
7421da177e4SLinus Torvalds 		pri = (struct iso_primary_descriptor *) sec;
7431da177e4SLinus Torvalds 		rootp = (struct iso_directory_record *)
7441da177e4SLinus Torvalds 			pri->root_directory_record;
7451da177e4SLinus Torvalds 		first_data_zone = isonum_733 (rootp->extent) +
7461da177e4SLinus Torvalds 			  	isonum_711 (rootp->ext_attr_length);
7471da177e4SLinus Torvalds 	}
7481da177e4SLinus Torvalds 
7491da177e4SLinus Torvalds 	/*
7501da177e4SLinus Torvalds 	 * We're all done using the volume descriptor, and may need
7511da177e4SLinus Torvalds 	 * to change the device blocksize, so release the buffer now.
7521da177e4SLinus Torvalds 	 */
7531da177e4SLinus Torvalds 	brelse(pri_bh);
7541da177e4SLinus Torvalds 	brelse(bh);
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 	/*
7571da177e4SLinus Torvalds 	 * Force the blocksize to 512 for 512 byte sectors.  The file
7581da177e4SLinus Torvalds 	 * read primitives really get it wrong in a bad way if we don't
7591da177e4SLinus Torvalds 	 * do this.
7601da177e4SLinus Torvalds 	 *
7611da177e4SLinus Torvalds 	 * Note - we should never be setting the blocksize to something
7621da177e4SLinus Torvalds 	 * less than the hardware sector size for the device.  If we
7631da177e4SLinus Torvalds 	 * do, we would end up having to read larger buffers and split
7641da177e4SLinus Torvalds 	 * out portions to satisfy requests.
7651da177e4SLinus Torvalds 	 *
7661da177e4SLinus Torvalds 	 * Note2- the idea here is that we want to deal with the optimal
7671da177e4SLinus Torvalds 	 * zonesize in the filesystem.  If we have it set to something less,
7681da177e4SLinus Torvalds 	 * then we have horrible problems with trying to piece together
7691da177e4SLinus Torvalds 	 * bits of adjacent blocks in order to properly read directory
7701da177e4SLinus Torvalds 	 * entries.  By forcing the blocksize in this way, we ensure
7711da177e4SLinus Torvalds 	 * that we will never be required to do this.
7721da177e4SLinus Torvalds 	 */
7731da177e4SLinus Torvalds 	sb_set_blocksize(s, orig_zonesize);
7741da177e4SLinus Torvalds 
7751da177e4SLinus Torvalds 	sbi->s_nls_iocharset = NULL;
7761da177e4SLinus Torvalds 
7771da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
7781da177e4SLinus Torvalds 	if (joliet_level && opt.utf8 == 0) {
7791da177e4SLinus Torvalds 		char * p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
7801da177e4SLinus Torvalds 		sbi->s_nls_iocharset = load_nls(p);
7811da177e4SLinus Torvalds 		if (! sbi->s_nls_iocharset) {
7821da177e4SLinus Torvalds 			/* Fail only if explicit charset specified */
7831da177e4SLinus Torvalds 			if (opt.iocharset)
7841da177e4SLinus Torvalds 				goto out_freesbi;
7851da177e4SLinus Torvalds 			sbi->s_nls_iocharset = load_nls_default();
7861da177e4SLinus Torvalds 		}
7871da177e4SLinus Torvalds 	}
7881da177e4SLinus Torvalds #endif
7891da177e4SLinus Torvalds 	s->s_op = &isofs_sops;
7901da177e4SLinus Torvalds 	s->s_export_op = &isofs_export_ops;
7911da177e4SLinus Torvalds 	sbi->s_mapping = opt.map;
7921da177e4SLinus Torvalds 	sbi->s_rock = (opt.rock == 'y' ? 2 : 0);
7931da177e4SLinus Torvalds 	sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/
7941da177e4SLinus Torvalds 	sbi->s_cruft = opt.cruft;
795*9769f4ebSJeremy White 	sbi->s_hide = opt.hide;
796*9769f4ebSJeremy White 	sbi->s_showassoc = opt.showassoc;
7971da177e4SLinus Torvalds 	sbi->s_uid = opt.uid;
7981da177e4SLinus Torvalds 	sbi->s_gid = opt.gid;
7991da177e4SLinus Torvalds 	sbi->s_utf8 = opt.utf8;
8001da177e4SLinus Torvalds 	sbi->s_nocompress = opt.nocompress;
8011da177e4SLinus Torvalds 	/*
8021da177e4SLinus Torvalds 	 * It would be incredibly stupid to allow people to mark every file
8031da177e4SLinus Torvalds 	 * on the disk as suid, so we merely allow them to set the default
8041da177e4SLinus Torvalds 	 * permissions.
8051da177e4SLinus Torvalds 	 */
8061da177e4SLinus Torvalds 	sbi->s_mode = opt.mode & 0777;
8071da177e4SLinus Torvalds 
8081da177e4SLinus Torvalds 	/*
8091da177e4SLinus Torvalds 	 * Read the root inode, which _may_ result in changing
8101da177e4SLinus Torvalds 	 * the s_rock flag. Once we have the final s_rock value,
8111da177e4SLinus Torvalds 	 * we then decide whether to use the Joliet descriptor.
8121da177e4SLinus Torvalds 	 */
8131da177e4SLinus Torvalds 	inode = isofs_iget(s, sbi->s_firstdatazone, 0);
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	/*
8161da177e4SLinus Torvalds 	 * If this disk has both Rock Ridge and Joliet on it, then we
8171da177e4SLinus Torvalds 	 * want to use Rock Ridge by default.  This can be overridden
8181da177e4SLinus Torvalds 	 * by using the norock mount option.  There is still one other
8191da177e4SLinus Torvalds 	 * possibility that is not taken into account: a Rock Ridge
8201da177e4SLinus Torvalds 	 * CD with Unicode names.  Until someone sees such a beast, it
8211da177e4SLinus Torvalds 	 * will not be supported.
8221da177e4SLinus Torvalds 	 */
8231da177e4SLinus Torvalds 	if (sbi->s_rock == 1) {
8241da177e4SLinus Torvalds 		joliet_level = 0;
8251da177e4SLinus Torvalds 	} else if (joliet_level) {
8261da177e4SLinus Torvalds 		sbi->s_rock = 0;
8271da177e4SLinus Torvalds 		if (sbi->s_firstdatazone != first_data_zone) {
8281da177e4SLinus Torvalds 			sbi->s_firstdatazone = first_data_zone;
8291da177e4SLinus Torvalds 			printk(KERN_DEBUG
8301da177e4SLinus Torvalds 				"ISOFS: changing to secondary root\n");
8311da177e4SLinus Torvalds 			iput(inode);
8321da177e4SLinus Torvalds 			inode = isofs_iget(s, sbi->s_firstdatazone, 0);
8331da177e4SLinus Torvalds 		}
8341da177e4SLinus Torvalds 	}
8351da177e4SLinus Torvalds 
8361da177e4SLinus Torvalds 	if (opt.check == 'u') {
8371da177e4SLinus Torvalds 		/* Only Joliet is case insensitive by default */
8381da177e4SLinus Torvalds 		if (joliet_level) opt.check = 'r';
8391da177e4SLinus Torvalds 		else opt.check = 's';
8401da177e4SLinus Torvalds 	}
8411da177e4SLinus Torvalds 	sbi->s_joliet_level = joliet_level;
8421da177e4SLinus Torvalds 
8431da177e4SLinus Torvalds 	/* check the root inode */
8441da177e4SLinus Torvalds 	if (!inode)
8451da177e4SLinus Torvalds 		goto out_no_root;
8461da177e4SLinus Torvalds 	if (!inode->i_op)
8471da177e4SLinus Torvalds 		goto out_bad_root;
8481da177e4SLinus Torvalds 	/* get the root dentry */
8491da177e4SLinus Torvalds 	s->s_root = d_alloc_root(inode);
8501da177e4SLinus Torvalds 	if (!(s->s_root))
8511da177e4SLinus Torvalds 		goto out_no_root;
8521da177e4SLinus Torvalds 
8531da177e4SLinus Torvalds 	table = 0;
8541da177e4SLinus Torvalds 	if (joliet_level) table += 2;
8551da177e4SLinus Torvalds 	if (opt.check == 'r') table++;
8561da177e4SLinus Torvalds 	s->s_root->d_op = &isofs_dentry_ops[table];
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 	if (opt.iocharset)
8591da177e4SLinus Torvalds 		kfree(opt.iocharset);
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 	return 0;
8621da177e4SLinus Torvalds 
8631da177e4SLinus Torvalds 	/*
8641da177e4SLinus Torvalds 	 * Display error messages and free resources.
8651da177e4SLinus Torvalds 	 */
8661da177e4SLinus Torvalds out_bad_root:
8671da177e4SLinus Torvalds 	printk(KERN_WARNING "isofs_fill_super: root inode not initialized\n");
8681da177e4SLinus Torvalds 	goto out_iput;
8691da177e4SLinus Torvalds out_no_root:
8701da177e4SLinus Torvalds 	printk(KERN_WARNING "isofs_fill_super: get root inode failed\n");
8711da177e4SLinus Torvalds out_iput:
8721da177e4SLinus Torvalds 	iput(inode);
8731da177e4SLinus Torvalds #ifdef CONFIG_JOLIET
8741da177e4SLinus Torvalds 	if (sbi->s_nls_iocharset)
8751da177e4SLinus Torvalds 		unload_nls(sbi->s_nls_iocharset);
8761da177e4SLinus Torvalds #endif
8771da177e4SLinus Torvalds 	goto out_freesbi;
8781da177e4SLinus Torvalds out_no_read:
8791da177e4SLinus Torvalds 	printk(KERN_WARNING "isofs_fill_super: "
8801da177e4SLinus Torvalds 		"bread failed, dev=%s, iso_blknum=%d, block=%d\n",
8811da177e4SLinus Torvalds 		s->s_id, iso_blknum, block);
8821da177e4SLinus Torvalds 	goto out_freesbi;
8831da177e4SLinus Torvalds out_bad_zone_size:
8841da177e4SLinus Torvalds 	printk(KERN_WARNING "Bad logical zone size %ld\n",
8851da177e4SLinus Torvalds 		sbi->s_log_zone_size);
8861da177e4SLinus Torvalds 	goto out_freebh;
8871da177e4SLinus Torvalds out_bad_size:
8881da177e4SLinus Torvalds 	printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n",
8891da177e4SLinus Torvalds 		orig_zonesize, opt.blocksize);
8901da177e4SLinus Torvalds 	goto out_freebh;
8911da177e4SLinus Torvalds out_unknown_format:
8921da177e4SLinus Torvalds 	if (!silent)
8931da177e4SLinus Torvalds 		printk(KERN_WARNING "Unable to identify CD-ROM format.\n");
8941da177e4SLinus Torvalds 
8951da177e4SLinus Torvalds out_freebh:
8961da177e4SLinus Torvalds 	brelse(bh);
8971da177e4SLinus Torvalds out_freesbi:
8981da177e4SLinus Torvalds 	if (opt.iocharset)
8991da177e4SLinus Torvalds 		kfree(opt.iocharset);
9001da177e4SLinus Torvalds 	kfree(sbi);
9011da177e4SLinus Torvalds 	s->s_fs_info = NULL;
9021da177e4SLinus Torvalds 	return -EINVAL;
9031da177e4SLinus Torvalds }
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds static int isofs_statfs (struct super_block *sb, struct kstatfs *buf)
9061da177e4SLinus Torvalds {
9071da177e4SLinus Torvalds 	buf->f_type = ISOFS_SUPER_MAGIC;
9081da177e4SLinus Torvalds 	buf->f_bsize = sb->s_blocksize;
9091da177e4SLinus Torvalds 	buf->f_blocks = (ISOFS_SB(sb)->s_nzones
9101da177e4SLinus Torvalds                   << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
9111da177e4SLinus Torvalds 	buf->f_bfree = 0;
9121da177e4SLinus Torvalds 	buf->f_bavail = 0;
9131da177e4SLinus Torvalds 	buf->f_files = ISOFS_SB(sb)->s_ninodes;
9141da177e4SLinus Torvalds 	buf->f_ffree = 0;
9151da177e4SLinus Torvalds 	buf->f_namelen = NAME_MAX;
9161da177e4SLinus Torvalds 	return 0;
9171da177e4SLinus Torvalds }
9181da177e4SLinus Torvalds 
9191da177e4SLinus Torvalds /*
9201da177e4SLinus Torvalds  * Get a set of blocks; filling in buffer_heads if already allocated
9211da177e4SLinus Torvalds  * or getblk() if they are not.  Returns the number of blocks inserted
9221da177e4SLinus Torvalds  * (0 == error.)
9231da177e4SLinus Torvalds  */
9241da177e4SLinus Torvalds int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
9251da177e4SLinus Torvalds 		     struct buffer_head **bh, unsigned long nblocks)
9261da177e4SLinus Torvalds {
9271da177e4SLinus Torvalds 	unsigned long b_off;
9281da177e4SLinus Torvalds 	unsigned offset, sect_size;
9291da177e4SLinus Torvalds 	unsigned int firstext;
9301da177e4SLinus Torvalds 	unsigned long nextblk, nextoff;
9311da177e4SLinus Torvalds 	long iblock = (long)iblock_s;
9321da177e4SLinus Torvalds 	int section, rv;
9331da177e4SLinus Torvalds 	struct iso_inode_info *ei = ISOFS_I(inode);
9341da177e4SLinus Torvalds 
9351da177e4SLinus Torvalds 	lock_kernel();
9361da177e4SLinus Torvalds 
9371da177e4SLinus Torvalds 	rv = 0;
9381da177e4SLinus Torvalds 	if (iblock < 0 || iblock != iblock_s) {
9391da177e4SLinus Torvalds 		printk("isofs_get_blocks: block number too large\n");
9401da177e4SLinus Torvalds 		goto abort;
9411da177e4SLinus Torvalds 	}
9421da177e4SLinus Torvalds 
9431da177e4SLinus Torvalds 	b_off = iblock;
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds 	offset    = 0;
9461da177e4SLinus Torvalds 	firstext  = ei->i_first_extent;
9471da177e4SLinus Torvalds 	sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
9481da177e4SLinus Torvalds 	nextblk   = ei->i_next_section_block;
9491da177e4SLinus Torvalds 	nextoff   = ei->i_next_section_offset;
9501da177e4SLinus Torvalds 	section   = 0;
9511da177e4SLinus Torvalds 
9521da177e4SLinus Torvalds 	while ( nblocks ) {
9531da177e4SLinus Torvalds 		/* If we are *way* beyond the end of the file, print a message.
9541da177e4SLinus Torvalds 		 * Access beyond the end of the file up to the next page boundary
9551da177e4SLinus Torvalds 		 * is normal, however because of the way the page cache works.
9561da177e4SLinus Torvalds 		 * In this case, we just return 0 so that we can properly fill
9571da177e4SLinus Torvalds 		 * the page with useless information without generating any
9581da177e4SLinus Torvalds 		 * I/O errors.
9591da177e4SLinus Torvalds 		 */
9601da177e4SLinus Torvalds 		if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
9611da177e4SLinus Torvalds 			printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n",
9621da177e4SLinus Torvalds 			       iblock, (unsigned long) inode->i_size);
9631da177e4SLinus Torvalds 			goto abort;
9641da177e4SLinus Torvalds 		}
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds 		if (nextblk) {
9671da177e4SLinus Torvalds 			while (b_off >= (offset + sect_size)) {
9681da177e4SLinus Torvalds 				struct inode *ninode;
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds 				offset += sect_size;
9711da177e4SLinus Torvalds 				if (nextblk == 0)
9721da177e4SLinus Torvalds 					goto abort;
9731da177e4SLinus Torvalds 				ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
9741da177e4SLinus Torvalds 				if (!ninode)
9751da177e4SLinus Torvalds 					goto abort;
9761da177e4SLinus Torvalds 				firstext  = ISOFS_I(ninode)->i_first_extent;
9771da177e4SLinus Torvalds 				sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
9781da177e4SLinus Torvalds 				nextblk   = ISOFS_I(ninode)->i_next_section_block;
9791da177e4SLinus Torvalds 				nextoff   = ISOFS_I(ninode)->i_next_section_offset;
9801da177e4SLinus Torvalds 				iput(ninode);
9811da177e4SLinus Torvalds 
9821da177e4SLinus Torvalds 				if (++section > 100) {
9831da177e4SLinus Torvalds 					printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
9841da177e4SLinus Torvalds 					printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
9851da177e4SLinus Torvalds 					       "nextblk=%lu nextoff=%lu\n",
9861da177e4SLinus Torvalds 					       iblock, firstext, (unsigned) sect_size,
9871da177e4SLinus Torvalds 					       nextblk, nextoff);
9881da177e4SLinus Torvalds 					goto abort;
9891da177e4SLinus Torvalds 				}
9901da177e4SLinus Torvalds 			}
9911da177e4SLinus Torvalds 		}
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds 		if ( *bh ) {
9941da177e4SLinus Torvalds 			map_bh(*bh, inode->i_sb, firstext + b_off - offset);
9951da177e4SLinus Torvalds 		} else {
9961da177e4SLinus Torvalds 			*bh = sb_getblk(inode->i_sb, firstext+b_off-offset);
9971da177e4SLinus Torvalds 			if ( !*bh )
9981da177e4SLinus Torvalds 				goto abort;
9991da177e4SLinus Torvalds 		}
10001da177e4SLinus Torvalds 		bh++;	/* Next buffer head */
10011da177e4SLinus Torvalds 		b_off++;	/* Next buffer offset */
10021da177e4SLinus Torvalds 		nblocks--;
10031da177e4SLinus Torvalds 		rv++;
10041da177e4SLinus Torvalds 	}
10051da177e4SLinus Torvalds 
10061da177e4SLinus Torvalds abort:
10071da177e4SLinus Torvalds 	unlock_kernel();
10081da177e4SLinus Torvalds 	return rv;
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds /*
10121da177e4SLinus Torvalds  * Used by the standard interfaces.
10131da177e4SLinus Torvalds  */
10141da177e4SLinus Torvalds static int isofs_get_block(struct inode *inode, sector_t iblock,
10151da177e4SLinus Torvalds 		    struct buffer_head *bh_result, int create)
10161da177e4SLinus Torvalds {
10171da177e4SLinus Torvalds 	if (create) {
10181da177e4SLinus Torvalds 		printk("isofs_get_block: Kernel tries to allocate a block\n");
10191da177e4SLinus Torvalds 		return -EROFS;
10201da177e4SLinus Torvalds 	}
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds 	return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO;
10231da177e4SLinus Torvalds }
10241da177e4SLinus Torvalds 
10251da177e4SLinus Torvalds static int isofs_bmap(struct inode *inode, sector_t block)
10261da177e4SLinus Torvalds {
10271da177e4SLinus Torvalds 	struct buffer_head dummy;
10281da177e4SLinus Torvalds 	int error;
10291da177e4SLinus Torvalds 
10301da177e4SLinus Torvalds 	dummy.b_state = 0;
10311da177e4SLinus Torvalds 	dummy.b_blocknr = -1000;
10321da177e4SLinus Torvalds 	error = isofs_get_block(inode, block, &dummy, 0);
10331da177e4SLinus Torvalds 	if (!error)
10341da177e4SLinus Torvalds 		return dummy.b_blocknr;
10351da177e4SLinus Torvalds 	return 0;
10361da177e4SLinus Torvalds }
10371da177e4SLinus Torvalds 
10381da177e4SLinus Torvalds struct buffer_head *isofs_bread(struct inode *inode, sector_t block)
10391da177e4SLinus Torvalds {
10401da177e4SLinus Torvalds 	sector_t blknr = isofs_bmap(inode, block);
10411da177e4SLinus Torvalds 	if (!blknr)
10421da177e4SLinus Torvalds 		return NULL;
10431da177e4SLinus Torvalds 	return sb_bread(inode->i_sb, blknr);
10441da177e4SLinus Torvalds }
10451da177e4SLinus Torvalds 
10461da177e4SLinus Torvalds static int isofs_readpage(struct file *file, struct page *page)
10471da177e4SLinus Torvalds {
10481da177e4SLinus Torvalds 	return block_read_full_page(page,isofs_get_block);
10491da177e4SLinus Torvalds }
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
10521da177e4SLinus Torvalds {
10531da177e4SLinus Torvalds 	return generic_block_bmap(mapping,block,isofs_get_block);
10541da177e4SLinus Torvalds }
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds static struct address_space_operations isofs_aops = {
10571da177e4SLinus Torvalds 	.readpage = isofs_readpage,
10581da177e4SLinus Torvalds 	.sync_page = block_sync_page,
10591da177e4SLinus Torvalds 	.bmap = _isofs_bmap
10601da177e4SLinus Torvalds };
10611da177e4SLinus Torvalds 
10621da177e4SLinus Torvalds static inline void test_and_set_uid(uid_t *p, uid_t value)
10631da177e4SLinus Torvalds {
10649eb7f2c6SAndrew Morton 	if (value)
10651da177e4SLinus Torvalds 		*p = value;
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds 
10681da177e4SLinus Torvalds static inline void test_and_set_gid(gid_t *p, gid_t value)
10691da177e4SLinus Torvalds {
10709eb7f2c6SAndrew Morton         if (value)
10711da177e4SLinus Torvalds                 *p = value;
10721da177e4SLinus Torvalds }
10731da177e4SLinus Torvalds 
10741da177e4SLinus Torvalds static int isofs_read_level3_size(struct inode *inode)
10751da177e4SLinus Torvalds {
10761da177e4SLinus Torvalds 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
10771da177e4SLinus Torvalds 	int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
10781da177e4SLinus Torvalds 	struct buffer_head * bh = NULL;
10791da177e4SLinus Torvalds 	unsigned long block, offset, block_saved, offset_saved;
10801da177e4SLinus Torvalds 	int i = 0;
10811da177e4SLinus Torvalds 	int more_entries = 0;
10821da177e4SLinus Torvalds 	struct iso_directory_record * tmpde = NULL;
10831da177e4SLinus Torvalds 	struct iso_inode_info *ei = ISOFS_I(inode);
10841da177e4SLinus Torvalds 
10851da177e4SLinus Torvalds 	inode->i_size = 0;
10861da177e4SLinus Torvalds 
10871da177e4SLinus Torvalds 	/* The first 16 blocks are reserved as the System Area.  Thus,
10881da177e4SLinus Torvalds 	 * no inodes can appear in block 0.  We use this to flag that
10891da177e4SLinus Torvalds 	 * this is the last section. */
10901da177e4SLinus Torvalds 	ei->i_next_section_block = 0;
10911da177e4SLinus Torvalds 	ei->i_next_section_offset = 0;
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 	block = ei->i_iget5_block;
10941da177e4SLinus Torvalds 	offset = ei->i_iget5_offset;
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 	do {
10971da177e4SLinus Torvalds 		struct iso_directory_record * de;
10981da177e4SLinus Torvalds 		unsigned int de_len;
10991da177e4SLinus Torvalds 
11001da177e4SLinus Torvalds 		if (!bh) {
11011da177e4SLinus Torvalds 			bh = sb_bread(inode->i_sb, block);
11021da177e4SLinus Torvalds 			if (!bh)
11031da177e4SLinus Torvalds 				goto out_noread;
11041da177e4SLinus Torvalds 		}
11051da177e4SLinus Torvalds 		de = (struct iso_directory_record *) (bh->b_data + offset);
11061da177e4SLinus Torvalds 		de_len = *(unsigned char *) de;
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 		if (de_len == 0) {
11091da177e4SLinus Torvalds 			brelse(bh);
11101da177e4SLinus Torvalds 			bh = NULL;
11111da177e4SLinus Torvalds 			++block;
11121da177e4SLinus Torvalds 			offset = 0;
11131da177e4SLinus Torvalds 			continue;
11141da177e4SLinus Torvalds 		}
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 		block_saved = block;
11171da177e4SLinus Torvalds 		offset_saved = offset;
11181da177e4SLinus Torvalds 		offset += de_len;
11191da177e4SLinus Torvalds 
11201da177e4SLinus Torvalds 		/* Make sure we have a full directory entry */
11211da177e4SLinus Torvalds 		if (offset >= bufsize) {
11221da177e4SLinus Torvalds 			int slop = bufsize - offset + de_len;
11231da177e4SLinus Torvalds 			if (!tmpde) {
11241da177e4SLinus Torvalds 				tmpde = kmalloc(256, GFP_KERNEL);
11251da177e4SLinus Torvalds 				if (!tmpde)
11261da177e4SLinus Torvalds 					goto out_nomem;
11271da177e4SLinus Torvalds 			}
11281da177e4SLinus Torvalds 			memcpy(tmpde, de, slop);
11291da177e4SLinus Torvalds 			offset &= bufsize - 1;
11301da177e4SLinus Torvalds 			block++;
11311da177e4SLinus Torvalds 			brelse(bh);
11321da177e4SLinus Torvalds 			bh = NULL;
11331da177e4SLinus Torvalds 			if (offset) {
11341da177e4SLinus Torvalds 				bh = sb_bread(inode->i_sb, block);
11351da177e4SLinus Torvalds 				if (!bh)
11361da177e4SLinus Torvalds 					goto out_noread;
11371da177e4SLinus Torvalds 				memcpy((void *)tmpde+slop, bh->b_data, offset);
11381da177e4SLinus Torvalds 			}
11391da177e4SLinus Torvalds 			de = tmpde;
11401da177e4SLinus Torvalds 		}
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 		inode->i_size += isonum_733(de->size);
11431da177e4SLinus Torvalds 		if (i == 1) {
11441da177e4SLinus Torvalds 			ei->i_next_section_block = block_saved;
11451da177e4SLinus Torvalds 			ei->i_next_section_offset = offset_saved;
11461da177e4SLinus Torvalds 		}
11471da177e4SLinus Torvalds 
11481da177e4SLinus Torvalds 		more_entries = de->flags[-high_sierra] & 0x80;
11491da177e4SLinus Torvalds 
11501da177e4SLinus Torvalds 		i++;
11511da177e4SLinus Torvalds 		if (i > 100)
11521da177e4SLinus Torvalds 			goto out_toomany;
11531da177e4SLinus Torvalds 	} while (more_entries);
11541da177e4SLinus Torvalds out:
11551da177e4SLinus Torvalds 	kfree(tmpde);
11561da177e4SLinus Torvalds 	if (bh)
11571da177e4SLinus Torvalds 		brelse(bh);
11581da177e4SLinus Torvalds 	return 0;
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds out_nomem:
11611da177e4SLinus Torvalds 	if (bh)
11621da177e4SLinus Torvalds 		brelse(bh);
11631da177e4SLinus Torvalds 	return -ENOMEM;
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds out_noread:
11661da177e4SLinus Torvalds 	printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
11671da177e4SLinus Torvalds 	if (tmpde)
11681da177e4SLinus Torvalds 		kfree(tmpde);
11691da177e4SLinus Torvalds 	return -EIO;
11701da177e4SLinus Torvalds 
11711da177e4SLinus Torvalds out_toomany:
11721da177e4SLinus Torvalds 	printk(KERN_INFO "isofs_read_level3_size: "
11731da177e4SLinus Torvalds 		"More than 100 file sections ?!?, aborting...\n"
11741da177e4SLinus Torvalds 	  	"isofs_read_level3_size: inode=%lu\n",
11751da177e4SLinus Torvalds 		inode->i_ino);
11761da177e4SLinus Torvalds 	goto out;
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds static void isofs_read_inode(struct inode *inode)
11801da177e4SLinus Torvalds {
11811da177e4SLinus Torvalds 	struct super_block *sb = inode->i_sb;
11821da177e4SLinus Torvalds 	struct isofs_sb_info *sbi = ISOFS_SB(sb);
11831da177e4SLinus Torvalds 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
11841da177e4SLinus Torvalds 	unsigned long block;
11851da177e4SLinus Torvalds 	int high_sierra = sbi->s_high_sierra;
11861da177e4SLinus Torvalds 	struct buffer_head * bh = NULL;
11871da177e4SLinus Torvalds 	struct iso_directory_record * de;
11881da177e4SLinus Torvalds 	struct iso_directory_record * tmpde = NULL;
11891da177e4SLinus Torvalds 	unsigned int de_len;
11901da177e4SLinus Torvalds 	unsigned long offset;
11911da177e4SLinus Torvalds 	struct iso_inode_info *ei = ISOFS_I(inode);
11921da177e4SLinus Torvalds 
11931da177e4SLinus Torvalds 	block = ei->i_iget5_block;
11941da177e4SLinus Torvalds 	bh = sb_bread(inode->i_sb, block);
11951da177e4SLinus Torvalds 	if (!bh)
11961da177e4SLinus Torvalds 		goto out_badread;
11971da177e4SLinus Torvalds 
11981da177e4SLinus Torvalds 	offset = ei->i_iget5_offset;
11991da177e4SLinus Torvalds 
12001da177e4SLinus Torvalds 	de = (struct iso_directory_record *) (bh->b_data + offset);
12011da177e4SLinus Torvalds 	de_len = *(unsigned char *) de;
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 	if (offset + de_len > bufsize) {
12041da177e4SLinus Torvalds 		int frag1 = bufsize - offset;
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 		tmpde = kmalloc(de_len, GFP_KERNEL);
12071da177e4SLinus Torvalds 		if (tmpde == NULL) {
12081da177e4SLinus Torvalds 			printk(KERN_INFO "isofs_read_inode: out of memory\n");
12091da177e4SLinus Torvalds 			goto fail;
12101da177e4SLinus Torvalds 		}
12111da177e4SLinus Torvalds 		memcpy(tmpde, bh->b_data + offset, frag1);
12121da177e4SLinus Torvalds 		brelse(bh);
12131da177e4SLinus Torvalds 		bh = sb_bread(inode->i_sb, ++block);
12141da177e4SLinus Torvalds 		if (!bh)
12151da177e4SLinus Torvalds 			goto out_badread;
12161da177e4SLinus Torvalds 		memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1);
12171da177e4SLinus Torvalds 		de = tmpde;
12181da177e4SLinus Torvalds 	}
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 	inode->i_ino = isofs_get_ino(ei->i_iget5_block,
12211da177e4SLinus Torvalds 				     ei->i_iget5_offset,
12221da177e4SLinus Torvalds 				     ISOFS_BUFFER_BITS(inode));
12231da177e4SLinus Torvalds 
12241da177e4SLinus Torvalds 	/* Assume it is a normal-format file unless told otherwise */
12251da177e4SLinus Torvalds 	ei->i_file_format = isofs_file_normal;
12261da177e4SLinus Torvalds 
12271da177e4SLinus Torvalds 	if (de->flags[-high_sierra] & 2) {
12281da177e4SLinus Torvalds 		inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
12291da177e4SLinus Torvalds 		inode->i_nlink = 1; /* Set to 1.  We know there are 2, but
12301da177e4SLinus Torvalds 				       the find utility tries to optimize
12311da177e4SLinus Torvalds 				       if it is 2, and it screws up.  It is
12321da177e4SLinus Torvalds 				       easier to give 1 which tells find to
12331da177e4SLinus Torvalds 				       do it the hard way. */
12341da177e4SLinus Torvalds 	} else {
12351da177e4SLinus Torvalds  		/* Everybody gets to read the file. */
12361da177e4SLinus Torvalds 		inode->i_mode = sbi->s_mode;
12371da177e4SLinus Torvalds 		inode->i_nlink = 1;
12381da177e4SLinus Torvalds 	        inode->i_mode |= S_IFREG;
12391da177e4SLinus Torvalds 	}
12401da177e4SLinus Torvalds 	inode->i_uid = sbi->s_uid;
12411da177e4SLinus Torvalds 	inode->i_gid = sbi->s_gid;
12421da177e4SLinus Torvalds 	inode->i_blocks = inode->i_blksize = 0;
12431da177e4SLinus Torvalds 
12441da177e4SLinus Torvalds 	ei->i_format_parm[0] = 0;
12451da177e4SLinus Torvalds 	ei->i_format_parm[1] = 0;
12461da177e4SLinus Torvalds 	ei->i_format_parm[2] = 0;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	ei->i_section_size = isonum_733 (de->size);
12491da177e4SLinus Torvalds 	if (de->flags[-high_sierra] & 0x80) {
12501da177e4SLinus Torvalds 		if(isofs_read_level3_size(inode)) goto fail;
12511da177e4SLinus Torvalds 	} else {
12521da177e4SLinus Torvalds 		ei->i_next_section_block = 0;
12531da177e4SLinus Torvalds 		ei->i_next_section_offset = 0;
12541da177e4SLinus Torvalds 		inode->i_size = isonum_733 (de->size);
12551da177e4SLinus Torvalds 	}
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	/*
12581da177e4SLinus Torvalds 	 * Some dipshit decided to store some other bit of information
12591da177e4SLinus Torvalds 	 * in the high byte of the file length.  Truncate size in case
12601da177e4SLinus Torvalds 	 * this CDROM was mounted with the cruft option.
12611da177e4SLinus Torvalds 	 */
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	if (sbi->s_cruft == 'y')
12641da177e4SLinus Torvalds 		inode->i_size &= 0x00ffffff;
12651da177e4SLinus Torvalds 
12661da177e4SLinus Torvalds 	if (de->interleave[0]) {
12671da177e4SLinus Torvalds 		printk("Interleaved files not (yet) supported.\n");
12681da177e4SLinus Torvalds 		inode->i_size = 0;
12691da177e4SLinus Torvalds 	}
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 	/* I have no idea what file_unit_size is used for, so
12721da177e4SLinus Torvalds 	   we will flag it for now */
12731da177e4SLinus Torvalds 	if (de->file_unit_size[0] != 0) {
12741da177e4SLinus Torvalds 		printk("File unit size != 0 for ISO file (%ld).\n",
12751da177e4SLinus Torvalds 		       inode->i_ino);
12761da177e4SLinus Torvalds 	}
12771da177e4SLinus Torvalds 
12781da177e4SLinus Torvalds 	/* I have no idea what other flag bits are used for, so
12791da177e4SLinus Torvalds 	   we will flag it for now */
12801da177e4SLinus Torvalds #ifdef DEBUG
12811da177e4SLinus Torvalds 	if((de->flags[-high_sierra] & ~2)!= 0){
12821da177e4SLinus Torvalds 		printk("Unusual flag settings for ISO file (%ld %x).\n",
12831da177e4SLinus Torvalds 		       inode->i_ino, de->flags[-high_sierra]);
12841da177e4SLinus Torvalds 	}
12851da177e4SLinus Torvalds #endif
12861da177e4SLinus Torvalds 
12871da177e4SLinus Torvalds 	inode->i_mtime.tv_sec =
12881da177e4SLinus Torvalds 	inode->i_atime.tv_sec =
12891da177e4SLinus Torvalds 	inode->i_ctime.tv_sec = iso_date(de->date, high_sierra);
12901da177e4SLinus Torvalds 	inode->i_mtime.tv_nsec =
12911da177e4SLinus Torvalds 	inode->i_atime.tv_nsec =
12921da177e4SLinus Torvalds 	inode->i_ctime.tv_nsec = 0;
12931da177e4SLinus Torvalds 
12941da177e4SLinus Torvalds 	ei->i_first_extent = (isonum_733 (de->extent) +
12951da177e4SLinus Torvalds 			      isonum_711 (de->ext_attr_length));
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds 	/* Set the number of blocks for stat() - should be done before RR */
12981da177e4SLinus Torvalds 	inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */
12991da177e4SLinus Torvalds 	inode->i_blocks  = (inode->i_size + 511) >> 9;
13001da177e4SLinus Torvalds 
13011da177e4SLinus Torvalds 	/*
13021da177e4SLinus Torvalds 	 * Now test for possible Rock Ridge extensions which will override
13031da177e4SLinus Torvalds 	 * some of these numbers in the inode structure.
13041da177e4SLinus Torvalds 	 */
13051da177e4SLinus Torvalds 
13061da177e4SLinus Torvalds 	if (!high_sierra) {
13071da177e4SLinus Torvalds 		parse_rock_ridge_inode(de, inode);
13081da177e4SLinus Torvalds 		/* if we want uid/gid set, override the rock ridge setting */
13091da177e4SLinus Torvalds 		test_and_set_uid(&inode->i_uid, sbi->s_uid);
13101da177e4SLinus Torvalds 		test_and_set_gid(&inode->i_gid, sbi->s_gid);
13111da177e4SLinus Torvalds 	}
13121da177e4SLinus Torvalds 
13131da177e4SLinus Torvalds 	/* Install the inode operations vector */
13141da177e4SLinus Torvalds 	if (S_ISREG(inode->i_mode)) {
13151da177e4SLinus Torvalds 		inode->i_fop = &generic_ro_fops;
13161da177e4SLinus Torvalds 		switch ( ei->i_file_format ) {
13171da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS
13181da177e4SLinus Torvalds 		case isofs_file_compressed:
13191da177e4SLinus Torvalds 			inode->i_data.a_ops = &zisofs_aops;
13201da177e4SLinus Torvalds 			break;
13211da177e4SLinus Torvalds #endif
13221da177e4SLinus Torvalds 		default:
13231da177e4SLinus Torvalds 			inode->i_data.a_ops = &isofs_aops;
13241da177e4SLinus Torvalds 			break;
13251da177e4SLinus Torvalds 		}
13261da177e4SLinus Torvalds 	} else if (S_ISDIR(inode->i_mode)) {
13271da177e4SLinus Torvalds 		inode->i_op = &isofs_dir_inode_operations;
13281da177e4SLinus Torvalds 		inode->i_fop = &isofs_dir_operations;
13291da177e4SLinus Torvalds 	} else if (S_ISLNK(inode->i_mode)) {
13301da177e4SLinus Torvalds 		inode->i_op = &page_symlink_inode_operations;
13311da177e4SLinus Torvalds 		inode->i_data.a_ops = &isofs_symlink_aops;
13321da177e4SLinus Torvalds 	} else
13331da177e4SLinus Torvalds 		/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
13341da177e4SLinus Torvalds 		init_special_inode(inode, inode->i_mode, inode->i_rdev);
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds out:
13371da177e4SLinus Torvalds 	if (tmpde)
13381da177e4SLinus Torvalds 		kfree(tmpde);
13391da177e4SLinus Torvalds 	if (bh)
13401da177e4SLinus Torvalds 		brelse(bh);
13411da177e4SLinus Torvalds 	return;
13421da177e4SLinus Torvalds 
13431da177e4SLinus Torvalds out_badread:
13441da177e4SLinus Torvalds 	printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
13451da177e4SLinus Torvalds fail:
13461da177e4SLinus Torvalds 	make_bad_inode(inode);
13471da177e4SLinus Torvalds 	goto out;
13481da177e4SLinus Torvalds }
13491da177e4SLinus Torvalds 
13501da177e4SLinus Torvalds struct isofs_iget5_callback_data {
13511da177e4SLinus Torvalds 	unsigned long block;
13521da177e4SLinus Torvalds 	unsigned long offset;
13531da177e4SLinus Torvalds };
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds static int isofs_iget5_test(struct inode *ino, void *data)
13561da177e4SLinus Torvalds {
13571da177e4SLinus Torvalds 	struct iso_inode_info *i = ISOFS_I(ino);
13581da177e4SLinus Torvalds 	struct isofs_iget5_callback_data *d =
13591da177e4SLinus Torvalds 		(struct isofs_iget5_callback_data*)data;
13601da177e4SLinus Torvalds 	return (i->i_iget5_block == d->block)
13611da177e4SLinus Torvalds 	       && (i->i_iget5_offset == d->offset);
13621da177e4SLinus Torvalds }
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds static int isofs_iget5_set(struct inode *ino, void *data)
13651da177e4SLinus Torvalds {
13661da177e4SLinus Torvalds 	struct iso_inode_info *i = ISOFS_I(ino);
13671da177e4SLinus Torvalds 	struct isofs_iget5_callback_data *d =
13681da177e4SLinus Torvalds 		(struct isofs_iget5_callback_data*)data;
13691da177e4SLinus Torvalds 	i->i_iget5_block = d->block;
13701da177e4SLinus Torvalds 	i->i_iget5_offset = d->offset;
13711da177e4SLinus Torvalds 	return 0;
13721da177e4SLinus Torvalds }
13731da177e4SLinus Torvalds 
13741da177e4SLinus Torvalds /* Store, in the inode's containing structure, the block and block
13751da177e4SLinus Torvalds  * offset that point to the underlying meta-data for the inode.  The
13761da177e4SLinus Torvalds  * code below is otherwise similar to the iget() code in
13771da177e4SLinus Torvalds  * include/linux/fs.h */
13781da177e4SLinus Torvalds struct inode *isofs_iget(struct super_block *sb,
13791da177e4SLinus Torvalds 			 unsigned long block,
13801da177e4SLinus Torvalds 			 unsigned long offset)
13811da177e4SLinus Torvalds {
13821da177e4SLinus Torvalds 	unsigned long hashval;
13831da177e4SLinus Torvalds 	struct inode *inode;
13841da177e4SLinus Torvalds 	struct isofs_iget5_callback_data data;
13851da177e4SLinus Torvalds 
13861da177e4SLinus Torvalds 	if (offset >= 1ul << sb->s_blocksize_bits)
13871da177e4SLinus Torvalds 		return NULL;
13881da177e4SLinus Torvalds 
13891da177e4SLinus Torvalds 	data.block = block;
13901da177e4SLinus Torvalds 	data.offset = offset;
13911da177e4SLinus Torvalds 
13921da177e4SLinus Torvalds 	hashval = (block << sb->s_blocksize_bits) | offset;
13931da177e4SLinus Torvalds 
13949eb7f2c6SAndrew Morton 	inode = iget5_locked(sb, hashval, &isofs_iget5_test,
13959eb7f2c6SAndrew Morton 			     &isofs_iget5_set, &data);
13961da177e4SLinus Torvalds 
13971da177e4SLinus Torvalds 	if (inode && (inode->i_state & I_NEW)) {
13981da177e4SLinus Torvalds 		sb->s_op->read_inode(inode);
13991da177e4SLinus Torvalds 		unlock_new_inode(inode);
14001da177e4SLinus Torvalds 	}
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 	return inode;
14031da177e4SLinus Torvalds }
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds static struct super_block *isofs_get_sb(struct file_system_type *fs_type,
14061da177e4SLinus Torvalds 	int flags, const char *dev_name, void *data)
14071da177e4SLinus Torvalds {
14081da177e4SLinus Torvalds 	return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
14091da177e4SLinus Torvalds }
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds static struct file_system_type iso9660_fs_type = {
14121da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
14131da177e4SLinus Torvalds 	.name		= "iso9660",
14141da177e4SLinus Torvalds 	.get_sb		= isofs_get_sb,
14151da177e4SLinus Torvalds 	.kill_sb	= kill_block_super,
14161da177e4SLinus Torvalds 	.fs_flags	= FS_REQUIRES_DEV,
14171da177e4SLinus Torvalds };
14181da177e4SLinus Torvalds 
14191da177e4SLinus Torvalds static int __init init_iso9660_fs(void)
14201da177e4SLinus Torvalds {
14211da177e4SLinus Torvalds 	int err = init_inodecache();
14221da177e4SLinus Torvalds 	if (err)
14231da177e4SLinus Torvalds 		goto out;
14241da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS
14251da177e4SLinus Torvalds 	err = zisofs_init();
14261da177e4SLinus Torvalds 	if (err)
14271da177e4SLinus Torvalds 		goto out1;
14281da177e4SLinus Torvalds #endif
14291da177e4SLinus Torvalds 	err = register_filesystem(&iso9660_fs_type);
14301da177e4SLinus Torvalds 	if (err)
14311da177e4SLinus Torvalds 		goto out2;
14321da177e4SLinus Torvalds 	return 0;
14331da177e4SLinus Torvalds out2:
14341da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS
14351da177e4SLinus Torvalds 	zisofs_cleanup();
14361da177e4SLinus Torvalds out1:
14371da177e4SLinus Torvalds #endif
14381da177e4SLinus Torvalds 	destroy_inodecache();
14391da177e4SLinus Torvalds out:
14401da177e4SLinus Torvalds 	return err;
14411da177e4SLinus Torvalds }
14421da177e4SLinus Torvalds 
14431da177e4SLinus Torvalds static void __exit exit_iso9660_fs(void)
14441da177e4SLinus Torvalds {
14451da177e4SLinus Torvalds         unregister_filesystem(&iso9660_fs_type);
14461da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS
14471da177e4SLinus Torvalds 	zisofs_cleanup();
14481da177e4SLinus Torvalds #endif
14491da177e4SLinus Torvalds 	destroy_inodecache();
14501da177e4SLinus Torvalds }
14511da177e4SLinus Torvalds 
14521da177e4SLinus Torvalds module_init(init_iso9660_fs)
14531da177e4SLinus Torvalds module_exit(exit_iso9660_fs)
14541da177e4SLinus Torvalds MODULE_LICENSE("GPL");
14551da177e4SLinus Torvalds /* Actual filesystem name is iso9660, as requested in filesystems.c */
14561da177e4SLinus Torvalds MODULE_ALIAS("iso9660");
1457