xref: /openbmc/linux/fs/befs/linuxvfs.c (revision 0a835948)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * linux/fs/befs/linuxvfs.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
9dac52fc1SFabian Frederick #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10dac52fc1SFabian Frederick 
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/slab.h>
131da177e4SLinus Torvalds #include <linux/fs.h>
141da177e4SLinus Torvalds #include <linux/errno.h>
151da177e4SLinus Torvalds #include <linux/stat.h>
161da177e4SLinus Torvalds #include <linux/nls.h>
171da177e4SLinus Torvalds #include <linux/buffer_head.h>
181da177e4SLinus Torvalds #include <linux/vfs.h>
191da177e4SLinus Torvalds #include <linux/parser.h>
201da177e4SLinus Torvalds #include <linux/namei.h>
2131aba059SEric W. Biederman #include <linux/sched.h>
225b825c3aSIngo Molnar #include <linux/cred.h>
23ac632f5bSLuis de Bethencourt #include <linux/exportfs.h>
243ab7947aSDavid Howells #include <linux/seq_file.h>
25621c1f42SChristoph Hellwig #include <linux/blkdev.h>
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include "befs.h"
281da177e4SLinus Torvalds #include "btree.h"
291da177e4SLinus Torvalds #include "inode.h"
301da177e4SLinus Torvalds #include "datastream.h"
311da177e4SLinus Torvalds #include "super.h"
321da177e4SLinus Torvalds #include "io.h"
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds MODULE_DESCRIPTION("BeOS File System (BeFS) driver");
351da177e4SLinus Torvalds MODULE_AUTHOR("Will Dyson");
361da177e4SLinus Torvalds MODULE_LICENSE("GPL");
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds /* The units the vfs expects inode->i_blocks to be in */
391da177e4SLinus Torvalds #define VFS_BLOCK_SIZE 512
401da177e4SLinus Torvalds 
41f0f49ef5SAl Viro static int befs_readdir(struct file *, struct dir_context *);
421da177e4SLinus Torvalds static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
432c69e205SMatthew Wilcox (Oracle) static int befs_read_folio(struct file *file, struct folio *folio);
441da177e4SLinus Torvalds static sector_t befs_bmap(struct address_space *mapping, sector_t block);
4562b80719SLuis de Bethencourt static struct dentry *befs_lookup(struct inode *, struct dentry *,
4662b80719SLuis de Bethencourt 				  unsigned int);
4796eb5419SDavid Howells static struct inode *befs_iget(struct super_block *, unsigned long);
481da177e4SLinus Torvalds static struct inode *befs_alloc_inode(struct super_block *sb);
4949f82a80SAl Viro static void befs_free_inode(struct inode *inode);
501da177e4SLinus Torvalds static void befs_destroy_inodecache(void);
51a13fe692SMatthew Wilcox (Oracle) static int befs_symlink_read_folio(struct file *, struct folio *);
521da177e4SLinus Torvalds static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
531da177e4SLinus Torvalds 			char **out, int *out_len);
541da177e4SLinus Torvalds static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
551da177e4SLinus Torvalds 			char **out, int *out_len);
561da177e4SLinus Torvalds static void befs_put_super(struct super_block *);
571da177e4SLinus Torvalds static int befs_remount(struct super_block *, int *, char *);
58726c3342SDavid Howells static int befs_statfs(struct dentry *, struct kstatfs *);
593ab7947aSDavid Howells static int befs_show_options(struct seq_file *, struct dentry *);
6009ad0eaeSFabian Frederick static int parse_options(char *, struct befs_mount_options *);
61ac632f5bSLuis de Bethencourt static struct dentry *befs_fh_to_dentry(struct super_block *sb,
62ac632f5bSLuis de Bethencourt 				struct fid *fid, int fh_len, int fh_type);
63ac632f5bSLuis de Bethencourt static struct dentry *befs_fh_to_parent(struct super_block *sb,
64ac632f5bSLuis de Bethencourt 				struct fid *fid, int fh_len, int fh_type);
65dcfd9b21SFabian Frederick static struct dentry *befs_get_parent(struct dentry *child);
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds static const struct super_operations befs_sops = {
681da177e4SLinus Torvalds 	.alloc_inode	= befs_alloc_inode,	/* allocate a new inode */
6949f82a80SAl Viro 	.free_inode	= befs_free_inode, /* deallocate an inode */
701da177e4SLinus Torvalds 	.put_super	= befs_put_super,	/* uninit super */
711da177e4SLinus Torvalds 	.statfs		= befs_statfs,	/* statfs */
721da177e4SLinus Torvalds 	.remount_fs	= befs_remount,
733ab7947aSDavid Howells 	.show_options	= befs_show_options,
741da177e4SLinus Torvalds };
751da177e4SLinus Torvalds 
761da177e4SLinus Torvalds /* slab cache for befs_inode_info objects */
77e18b890bSChristoph Lameter static struct kmem_cache *befs_inode_cachep;
781da177e4SLinus Torvalds 
794b6f5d20SArjan van de Ven static const struct file_operations befs_dir_operations = {
801da177e4SLinus Torvalds 	.read		= generic_read_dir,
81e23e9aa7SAl Viro 	.iterate_shared	= befs_readdir,
8259af1584SAl Viro 	.llseek		= generic_file_llseek,
831da177e4SLinus Torvalds };
841da177e4SLinus Torvalds 
85754661f1SArjan van de Ven static const struct inode_operations befs_dir_inode_operations = {
861da177e4SLinus Torvalds 	.lookup		= befs_lookup,
871da177e4SLinus Torvalds };
881da177e4SLinus Torvalds 
89f5e54d6eSChristoph Hellwig static const struct address_space_operations befs_aops = {
902c69e205SMatthew Wilcox (Oracle) 	.read_folio	= befs_read_folio,
911da177e4SLinus Torvalds 	.bmap		= befs_bmap,
921da177e4SLinus Torvalds };
931da177e4SLinus Torvalds 
9411803f97SAl Viro static const struct address_space_operations befs_symlink_aops = {
95a13fe692SMatthew Wilcox (Oracle) 	.read_folio	= befs_symlink_read_folio,
961da177e4SLinus Torvalds };
971da177e4SLinus Torvalds 
98ac632f5bSLuis de Bethencourt static const struct export_operations befs_export_operations = {
99ac632f5bSLuis de Bethencourt 	.fh_to_dentry	= befs_fh_to_dentry,
100ac632f5bSLuis de Bethencourt 	.fh_to_parent	= befs_fh_to_parent,
101dcfd9b21SFabian Frederick 	.get_parent	= befs_get_parent,
102ac632f5bSLuis de Bethencourt };
103ac632f5bSLuis de Bethencourt 
1041da177e4SLinus Torvalds /*
1052c69e205SMatthew Wilcox (Oracle)  * Called by generic_file_read() to read a folio of data
1061da177e4SLinus Torvalds  *
1071da177e4SLinus Torvalds  * In turn, simply calls a generic block read function and
1081da177e4SLinus Torvalds  * passes it the address of befs_get_block, for mapping file
1091da177e4SLinus Torvalds  * positions to disk blocks.
1101da177e4SLinus Torvalds  */
befs_read_folio(struct file * file,struct folio * folio)111ac09d88bSMatthew Wilcox (Oracle) static int befs_read_folio(struct file *file, struct folio *folio)
1121da177e4SLinus Torvalds {
1132c69e205SMatthew Wilcox (Oracle) 	return block_read_full_folio(folio, befs_get_block);
1141da177e4SLinus Torvalds }
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds static sector_t
befs_bmap(struct address_space * mapping,sector_t block)1171da177e4SLinus Torvalds befs_bmap(struct address_space *mapping, sector_t block)
1181da177e4SLinus Torvalds {
1191da177e4SLinus Torvalds 	return generic_block_bmap(mapping, block, befs_get_block);
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds /*
1231da177e4SLinus Torvalds  * Generic function to map a file position (block) to a
1241da177e4SLinus Torvalds  * disk offset (passed back in bh_result).
1251da177e4SLinus Torvalds  *
1261da177e4SLinus Torvalds  * Used by many higher level functions.
1271da177e4SLinus Torvalds  *
1281da177e4SLinus Torvalds  * Calls befs_fblock2brun() in datastream.c to do the real work.
1291da177e4SLinus Torvalds  */
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds static int
befs_get_block(struct inode * inode,sector_t block,struct buffer_head * bh_result,int create)1321da177e4SLinus Torvalds befs_get_block(struct inode *inode, sector_t block,
1331da177e4SLinus Torvalds 	       struct buffer_head *bh_result, int create)
1341da177e4SLinus Torvalds {
1351da177e4SLinus Torvalds 	struct super_block *sb = inode->i_sb;
1361da177e4SLinus Torvalds 	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
1371da177e4SLinus Torvalds 	befs_block_run run = BAD_IADDR;
138abcf9116SSalah Triki 	int res;
1391da177e4SLinus Torvalds 	ulong disk_off;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld",
142dac52fc1SFabian Frederick 		   (unsigned long)inode->i_ino, (long)block);
1431da177e4SLinus Torvalds 	if (create) {
1441da177e4SLinus Torvalds 		befs_error(sb, "befs_get_block() was asked to write to "
145dac52fc1SFabian Frederick 			   "block %ld in inode %lu", (long)block,
146dac52fc1SFabian Frederick 			   (unsigned long)inode->i_ino);
1471da177e4SLinus Torvalds 		return -EPERM;
1481da177e4SLinus Torvalds 	}
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	res = befs_fblock2brun(sb, ds, block, &run);
1511da177e4SLinus Torvalds 	if (res != BEFS_OK) {
1521da177e4SLinus Torvalds 		befs_error(sb,
153dac52fc1SFabian Frederick 			   "<--- %s for inode %lu, block %ld ERROR",
154dac52fc1SFabian Frederick 			   __func__, (unsigned long)inode->i_ino,
155dac52fc1SFabian Frederick 			   (long)block);
1561da177e4SLinus Torvalds 		return -EFBIG;
1571da177e4SLinus Torvalds 	}
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	disk_off = (ulong) iaddr2blockno(sb, &run);
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	map_bh(bh_result, inode->i_sb, disk_off);
1621da177e4SLinus Torvalds 
163dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s for inode %lu, block %ld, disk address %lu",
164dac52fc1SFabian Frederick 		  __func__, (unsigned long)inode->i_ino, (long)block,
165dac52fc1SFabian Frederick 		  (unsigned long)disk_off);
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds 	return 0;
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds static struct dentry *
befs_lookup(struct inode * dir,struct dentry * dentry,unsigned int flags)17100cd8dd3SAl Viro befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
1721da177e4SLinus Torvalds {
173c9408763SSalah Triki 	struct inode *inode;
1741da177e4SLinus Torvalds 	struct super_block *sb = dir->i_sb;
17522341d8fSAl Viro 	const befs_data_stream *ds = &BEFS_I(dir)->i_data.ds;
1761da177e4SLinus Torvalds 	befs_off_t offset;
1771da177e4SLinus Torvalds 	int ret;
1781da177e4SLinus Torvalds 	int utfnamelen;
1791da177e4SLinus Torvalds 	char *utfname;
1801da177e4SLinus Torvalds 	const char *name = dentry->d_name.name;
1811da177e4SLinus Torvalds 
182a455589fSAl Viro 	befs_debug(sb, "---> %s name %pd inode %ld", __func__,
183a455589fSAl Viro 		   dentry, dir->i_ino);
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 	/* Convert to UTF-8 */
1861da177e4SLinus Torvalds 	if (BEFS_SB(sb)->nls) {
1871da177e4SLinus Torvalds 		ret =
1881da177e4SLinus Torvalds 		    befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen);
1891da177e4SLinus Torvalds 		if (ret < 0) {
190dac52fc1SFabian Frederick 			befs_debug(sb, "<--- %s ERROR", __func__);
1911da177e4SLinus Torvalds 			return ERR_PTR(ret);
1921da177e4SLinus Torvalds 		}
1931da177e4SLinus Torvalds 		ret = befs_btree_find(sb, ds, utfname, &offset);
1941da177e4SLinus Torvalds 		kfree(utfname);
1951da177e4SLinus Torvalds 
1961da177e4SLinus Torvalds 	} else {
197f7769f9cSLuis de Bethencourt 		ret = befs_btree_find(sb, ds, name, &offset);
1981da177e4SLinus Torvalds 	}
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	if (ret == BEFS_BT_NOT_FOUND) {
201a455589fSAl Viro 		befs_debug(sb, "<--- %s %pd not found", __func__, dentry);
202f4e4d434SAl Viro 		inode = NULL;
2031da177e4SLinus Torvalds 	} else if (ret != BEFS_OK || offset == 0) {
2044c3897ccSLuis de Bethencourt 		befs_error(sb, "<--- %s Error", __func__);
205f4e4d434SAl Viro 		inode = ERR_PTR(-ENODATA);
206f4e4d434SAl Viro 	} else {
20796eb5419SDavid Howells 		inode = befs_iget(dir->i_sb, (ino_t) offset);
208f4e4d434SAl Viro 	}
209dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
2101da177e4SLinus Torvalds 
211f4e4d434SAl Viro 	return d_splice_alias(inode, dentry);
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds static int
befs_readdir(struct file * file,struct dir_context * ctx)215f0f49ef5SAl Viro befs_readdir(struct file *file, struct dir_context *ctx)
2161da177e4SLinus Torvalds {
217f0f49ef5SAl Viro 	struct inode *inode = file_inode(file);
2181da177e4SLinus Torvalds 	struct super_block *sb = inode->i_sb;
21922341d8fSAl Viro 	const befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
2201da177e4SLinus Torvalds 	befs_off_t value;
2211da177e4SLinus Torvalds 	int result;
2221da177e4SLinus Torvalds 	size_t keysize;
2231da177e4SLinus Torvalds 	char keybuf[BEFS_NAME_LEN + 1];
2241da177e4SLinus Torvalds 
225a455589fSAl Viro 	befs_debug(sb, "---> %s name %pD, inode %ld, ctx->pos %lld",
226a455589fSAl Viro 		  __func__, file, inode->i_ino, ctx->pos);
2271da177e4SLinus Torvalds 
2289ae51a32SLuis de Bethencourt 	while (1) {
229f0f49ef5SAl Viro 		result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1,
2301da177e4SLinus Torvalds 					 keybuf, &keysize, &value);
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 		if (result == BEFS_ERR) {
233dac52fc1SFabian Frederick 			befs_debug(sb, "<--- %s ERROR", __func__);
234a455589fSAl Viro 			befs_error(sb, "IO error reading %pD (inode %lu)",
235a455589fSAl Viro 				   file, inode->i_ino);
2361da177e4SLinus Torvalds 			return -EIO;
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 		} else if (result == BEFS_BT_END) {
239dac52fc1SFabian Frederick 			befs_debug(sb, "<--- %s END", __func__);
2401da177e4SLinus Torvalds 			return 0;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 		} else if (result == BEFS_BT_EMPTY) {
243dac52fc1SFabian Frederick 			befs_debug(sb, "<--- %s Empty directory", __func__);
2441da177e4SLinus Torvalds 			return 0;
2451da177e4SLinus Torvalds 		}
2461da177e4SLinus Torvalds 
2471da177e4SLinus Torvalds 		/* Convert to NLS */
2481da177e4SLinus Torvalds 		if (BEFS_SB(sb)->nls) {
249f0f49ef5SAl Viro 			char *nlsname;
250f0f49ef5SAl Viro 			int nlsnamelen;
2519ae51a32SLuis de Bethencourt 
2521da177e4SLinus Torvalds 			result =
2539ae51a32SLuis de Bethencourt 			    befs_utf2nls(sb, keybuf, keysize, &nlsname,
2549ae51a32SLuis de Bethencourt 					 &nlsnamelen);
2551da177e4SLinus Torvalds 			if (result < 0) {
256dac52fc1SFabian Frederick 				befs_debug(sb, "<--- %s ERROR", __func__);
2571da177e4SLinus Torvalds 				return result;
2581da177e4SLinus Torvalds 			}
259f0f49ef5SAl Viro 			if (!dir_emit(ctx, nlsname, nlsnamelen,
26050858ef9SLuis de Bethencourt 				      (ino_t) value, DT_UNKNOWN)) {
2611da177e4SLinus Torvalds 				kfree(nlsname);
262f0f49ef5SAl Viro 				return 0;
2631da177e4SLinus Torvalds 			}
264f0f49ef5SAl Viro 			kfree(nlsname);
265f0f49ef5SAl Viro 		} else {
266f0f49ef5SAl Viro 			if (!dir_emit(ctx, keybuf, keysize,
26750858ef9SLuis de Bethencourt 				      (ino_t) value, DT_UNKNOWN))
268f0f49ef5SAl Viro 				return 0;
269f0f49ef5SAl Viro 		}
270f0f49ef5SAl Viro 		ctx->pos++;
2719ae51a32SLuis de Bethencourt 	}
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds static struct inode *
befs_alloc_inode(struct super_block * sb)2751da177e4SLinus Torvalds befs_alloc_inode(struct super_block *sb)
2761da177e4SLinus Torvalds {
2771da177e4SLinus Torvalds 	struct befs_inode_info *bi;
278111d639dSFabian Frederick 
279fd60b288SMuchun Song 	bi = alloc_inode_sb(sb, befs_inode_cachep, GFP_KERNEL);
2801da177e4SLinus Torvalds 	if (!bi)
2811da177e4SLinus Torvalds 		return NULL;
2821da177e4SLinus Torvalds 	return &bi->vfs_inode;
2831da177e4SLinus Torvalds }
2841da177e4SLinus Torvalds 
befs_free_inode(struct inode * inode)28549f82a80SAl Viro static void befs_free_inode(struct inode *inode)
2861da177e4SLinus Torvalds {
2871da177e4SLinus Torvalds 	kmem_cache_free(befs_inode_cachep, BEFS_I(inode));
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
init_once(void * foo)29051cc5068SAlexey Dobriyan static void init_once(void *foo)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	struct befs_inode_info *bi = (struct befs_inode_info *) foo;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	inode_init_once(&bi->vfs_inode);
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds 
befs_iget(struct super_block * sb,unsigned long ino)29796eb5419SDavid Howells static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
2981da177e4SLinus Torvalds {
299e4c7f5b1SSalah Triki 	struct buffer_head *bh;
30044ad8098SSalah Triki 	befs_inode *raw_inode;
301038428fcSFabian Frederick 	struct befs_sb_info *befs_sb = BEFS_SB(sb);
302d6e02033SSalah Triki 	struct befs_inode_info *befs_ino;
30396eb5419SDavid Howells 	struct inode *inode;
3041da177e4SLinus Torvalds 
305dac52fc1SFabian Frederick 	befs_debug(sb, "---> %s inode = %lu", __func__, ino);
30696eb5419SDavid Howells 
30796eb5419SDavid Howells 	inode = iget_locked(sb, ino);
308ac34a1b3SRakesh Pandit 	if (!inode)
309ac34a1b3SRakesh Pandit 		return ERR_PTR(-ENOMEM);
31096eb5419SDavid Howells 	if (!(inode->i_state & I_NEW))
31196eb5419SDavid Howells 		return inode;
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds 	befs_ino = BEFS_I(inode);
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 	/* convert from vfs's inode number to befs's inode number */
3161da177e4SLinus Torvalds 	befs_ino->i_inode_num = blockno2iaddr(sb, inode->i_ino);
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 	befs_debug(sb, "  real inode number [%u, %hu, %hu]",
3191da177e4SLinus Torvalds 		   befs_ino->i_inode_num.allocation_group,
3201da177e4SLinus Torvalds 		   befs_ino->i_inode_num.start, befs_ino->i_inode_num.len);
3211da177e4SLinus Torvalds 
322f7f67540SSalah Triki 	bh = sb_bread(sb, inode->i_ino);
3231da177e4SLinus Torvalds 	if (!bh) {
3241da177e4SLinus Torvalds 		befs_error(sb, "unable to read inode block - "
3251da177e4SLinus Torvalds 			   "inode = %lu", inode->i_ino);
3260418726bSAdrian Bunk 		goto unacquire_none;
3271da177e4SLinus Torvalds 	}
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 	raw_inode = (befs_inode *) bh->b_data;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	befs_dump_inode(sb, raw_inode);
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) {
3341da177e4SLinus Torvalds 		befs_error(sb, "Bad inode: %lu", inode->i_ino);
3350418726bSAdrian Bunk 		goto unacquire_bh;
3361da177e4SLinus Torvalds 	}
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds 	inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode);
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	/*
3411da177e4SLinus Torvalds 	 * set uid and gid.  But since current BeOS is single user OS, so
3421da177e4SLinus Torvalds 	 * you can change by "uid" or "gid" options.
3431da177e4SLinus Torvalds 	 */
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds 	inode->i_uid = befs_sb->mount_opts.use_uid ?
34631aba059SEric W. Biederman 		befs_sb->mount_opts.uid :
34731aba059SEric W. Biederman 		make_kuid(&init_user_ns, fs32_to_cpu(sb, raw_inode->uid));
3481da177e4SLinus Torvalds 	inode->i_gid = befs_sb->mount_opts.use_gid ?
34931aba059SEric W. Biederman 		befs_sb->mount_opts.gid :
35031aba059SEric W. Biederman 		make_kgid(&init_user_ns, fs32_to_cpu(sb, raw_inode->gid));
3511da177e4SLinus Torvalds 
352bfe86848SMiklos Szeredi 	set_nlink(inode, 1);
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	/*
3551da177e4SLinus Torvalds 	 * BEFS's time is 64 bits, but current VFS is 32 bits...
3561da177e4SLinus Torvalds 	 * BEFS don't have access time. Nor inode change time. VFS
3571da177e4SLinus Torvalds 	 * doesn't have creation time.
3581da177e4SLinus Torvalds 	 * Also, the lower 16 bits of the last_modified_time and
3591da177e4SLinus Torvalds 	 * create_time are just a counter to help ensure uniqueness
3601da177e4SLinus Torvalds 	 * for indexing purposes. (PFD, page 54)
3611da177e4SLinus Torvalds 	 */
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	inode->i_mtime.tv_sec =
3641da177e4SLinus Torvalds 	    fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16;
3651da177e4SLinus Torvalds 	inode->i_mtime.tv_nsec = 0;   /* lower 16 bits are not a time */
366*0a835948SJeff Layton 	inode_set_ctime_to_ts(inode, inode->i_mtime);
3671da177e4SLinus Torvalds 	inode->i_atime = inode->i_mtime;
3681da177e4SLinus Torvalds 
3691da177e4SLinus Torvalds 	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
3701da177e4SLinus Torvalds 	befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent);
3711da177e4SLinus Torvalds 	befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes);
3721da177e4SLinus Torvalds 	befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags);
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){
3751da177e4SLinus Torvalds 		inode->i_size = 0;
3761da177e4SLinus Torvalds 		inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
37773919280SAzeem Shaikh 		strscpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
37839d7a29fSFabian Frederick 			BEFS_SYMLINK_LEN);
3791da177e4SLinus Torvalds 	} else {
3801da177e4SLinus Torvalds 		int num_blks;
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 		befs_ino->i_data.ds =
383e0e3d32bSJesper Juhl 		    fsds_to_cpu(sb, &raw_inode->data.datastream);
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 		num_blks = befs_count_blocks(sb, &befs_ino->i_data.ds);
3861da177e4SLinus Torvalds 		inode->i_blocks =
3871da177e4SLinus Torvalds 		    num_blks * (befs_sb->block_size / VFS_BLOCK_SIZE);
3881da177e4SLinus Torvalds 		inode->i_size = befs_ino->i_data.ds.size;
3891da177e4SLinus Torvalds 	}
3901da177e4SLinus Torvalds 
3911da177e4SLinus Torvalds 	inode->i_mapping->a_ops = &befs_aops;
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	if (S_ISREG(inode->i_mode)) {
3942cf06916SChristoph Hellwig 		inode->i_fop = &generic_ro_fops;
3951da177e4SLinus Torvalds 	} else if (S_ISDIR(inode->i_mode)) {
3961da177e4SLinus Torvalds 		inode->i_op = &befs_dir_inode_operations;
3971da177e4SLinus Torvalds 		inode->i_fop = &befs_dir_operations;
3981da177e4SLinus Torvalds 	} else if (S_ISLNK(inode->i_mode)) {
399d0deec19SAl Viro 		if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
40011803f97SAl Viro 			inode->i_op = &page_symlink_inode_operations;
40121fc61c7SAl Viro 			inode_nohighmem(inode);
40211803f97SAl Viro 			inode->i_mapping->a_ops = &befs_symlink_aops;
403d0deec19SAl Viro 		} else {
404d0deec19SAl Viro 			inode->i_link = befs_ino->i_data.symlink;
405d0deec19SAl Viro 			inode->i_op = &simple_symlink_inode_operations;
406d0deec19SAl Viro 		}
4071da177e4SLinus Torvalds 	} else {
4081da177e4SLinus Torvalds 		befs_error(sb, "Inode %lu is not a regular file, "
4091da177e4SLinus Torvalds 			   "directory or symlink. THAT IS WRONG! BeFS has no "
4101da177e4SLinus Torvalds 			   "on disk special files", inode->i_ino);
4110418726bSAdrian Bunk 		goto unacquire_bh;
4121da177e4SLinus Torvalds 	}
4131da177e4SLinus Torvalds 
4141da177e4SLinus Torvalds 	brelse(bh);
415dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
41696eb5419SDavid Howells 	unlock_new_inode(inode);
41796eb5419SDavid Howells 	return inode;
4181da177e4SLinus Torvalds 
4190418726bSAdrian Bunk unacquire_bh:
4201da177e4SLinus Torvalds 	brelse(bh);
4211da177e4SLinus Torvalds 
4220418726bSAdrian Bunk unacquire_none:
42396eb5419SDavid Howells 	iget_failed(inode);
424dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s - Bad inode", __func__);
42533c712b4SSalah Triki 	return ERR_PTR(-EIO);
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds /* Initialize the inode cache. Called at fs setup.
4291da177e4SLinus Torvalds  *
4301da177e4SLinus Torvalds  * Taken from NFS implementation by Al Viro.
4311da177e4SLinus Torvalds  */
43291a52ab7SFabian Frederick static int __init
befs_init_inodecache(void)4331da177e4SLinus Torvalds befs_init_inodecache(void)
4341da177e4SLinus Torvalds {
4350fc256d3SDavid Windsor 	befs_inode_cachep = kmem_cache_create_usercopy("befs_inode_cache",
4360fc256d3SDavid Windsor 				sizeof(struct befs_inode_info), 0,
4370fc256d3SDavid Windsor 				(SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD|
4380fc256d3SDavid Windsor 					SLAB_ACCOUNT),
4390fc256d3SDavid Windsor 				offsetof(struct befs_inode_info,
4400fc256d3SDavid Windsor 					i_data.symlink),
4410fc256d3SDavid Windsor 				sizeof_field(struct befs_inode_info,
4420fc256d3SDavid Windsor 					i_data.symlink),
44320c2df83SPaul Mundt 				init_once);
444c08f1cb6SSalah Triki 	if (befs_inode_cachep == NULL)
4451da177e4SLinus Torvalds 		return -ENOMEM;
446c08f1cb6SSalah Triki 
4471da177e4SLinus Torvalds 	return 0;
4481da177e4SLinus Torvalds }
4491da177e4SLinus Torvalds 
4501da177e4SLinus Torvalds /* Called at fs teardown.
4511da177e4SLinus Torvalds  *
4521da177e4SLinus Torvalds  * Taken from NFS implementation by Al Viro.
4531da177e4SLinus Torvalds  */
4541da177e4SLinus Torvalds static void
befs_destroy_inodecache(void)4551da177e4SLinus Torvalds befs_destroy_inodecache(void)
4561da177e4SLinus Torvalds {
4578c0a8537SKirill A. Shutemov 	/*
4588c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
4598c0a8537SKirill A. Shutemov 	 * destroy cache.
4608c0a8537SKirill A. Shutemov 	 */
4618c0a8537SKirill A. Shutemov 	rcu_barrier();
4621a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(befs_inode_cachep);
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds 
4651da177e4SLinus Torvalds /*
4661da177e4SLinus Torvalds  * The inode of symbolic link is different to data stream.
4671da177e4SLinus Torvalds  * The data stream become link name. Unless the LONG_SYMLINK
4681da177e4SLinus Torvalds  * flag is set.
4691da177e4SLinus Torvalds  */
befs_symlink_read_folio(struct file * unused,struct folio * folio)470a13fe692SMatthew Wilcox (Oracle) static int befs_symlink_read_folio(struct file *unused, struct folio *folio)
4711da177e4SLinus Torvalds {
472ac09d88bSMatthew Wilcox (Oracle) 	struct inode *inode = folio->mapping->host;
47311803f97SAl Viro 	struct super_block *sb = inode->i_sb;
47411803f97SAl Viro 	struct befs_inode_info *befs_ino = BEFS_I(inode);
4751da177e4SLinus Torvalds 	befs_data_stream *data = &befs_ino->i_data.ds;
4761da177e4SLinus Torvalds 	befs_off_t len = data->size;
477ac09d88bSMatthew Wilcox (Oracle) 	char *link = folio_address(folio);
4781da177e4SLinus Torvalds 
47911803f97SAl Viro 	if (len == 0 || len > PAGE_SIZE) {
480338d0f0aSTimo Warns 		befs_error(sb, "Long symlink with illegal length");
48111803f97SAl Viro 		goto fail;
482680baacbSAl Viro 	}
4831da177e4SLinus Torvalds 	befs_debug(sb, "Follow long symlink");
4841da177e4SLinus Torvalds 
485680baacbSAl Viro 	if (befs_read_lsymlink(sb, data, link, len) != len) {
4861da177e4SLinus Torvalds 		befs_error(sb, "Failed to read entire long symlink");
48711803f97SAl Viro 		goto fail;
488680baacbSAl Viro 	}
4897df5fa06SDuane Griffin 	link[len - 1] = '\0';
490ac09d88bSMatthew Wilcox (Oracle) 	folio_mark_uptodate(folio);
491ac09d88bSMatthew Wilcox (Oracle) 	folio_unlock(folio);
49211803f97SAl Viro 	return 0;
49311803f97SAl Viro fail:
494ac09d88bSMatthew Wilcox (Oracle) 	folio_set_error(folio);
495ac09d88bSMatthew Wilcox (Oracle) 	folio_unlock(folio);
49611803f97SAl Viro 	return -EIO;
4971da177e4SLinus Torvalds }
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds /*
5001da177e4SLinus Torvalds  * UTF-8 to NLS charset convert routine
5011da177e4SLinus Torvalds  *
5021ca7087eSLuis de Bethencourt  * Uses uni2char() / char2uni() rather than the nls tables directly
5031da177e4SLinus Torvalds  */
5041da177e4SLinus Torvalds static int
befs_utf2nls(struct super_block * sb,const char * in,int in_len,char ** out,int * out_len)5051da177e4SLinus Torvalds befs_utf2nls(struct super_block *sb, const char *in,
5061da177e4SLinus Torvalds 	     int in_len, char **out, int *out_len)
5071da177e4SLinus Torvalds {
5081da177e4SLinus Torvalds 	struct nls_table *nls = BEFS_SB(sb)->nls;
5091da177e4SLinus Torvalds 	int i, o;
51074675a58SAlan Stern 	unicode_t uni;
5111da177e4SLinus Torvalds 	int unilen, utflen;
5121da177e4SLinus Torvalds 	char *result;
51394f563c4SDiego Calleja 	/* The utf8->nls conversion won't make the final nls string bigger
51494f563c4SDiego Calleja 	 * than the utf one, but if the string is pure ascii they'll have the
51594f563c4SDiego Calleja 	 * same width and an extra char is needed to save the additional \0
51694f563c4SDiego Calleja 	 */
51794f563c4SDiego Calleja 	int maxlen = in_len + 1;
5181da177e4SLinus Torvalds 
519dac52fc1SFabian Frederick 	befs_debug(sb, "---> %s", __func__);
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	if (!nls) {
522dac52fc1SFabian Frederick 		befs_error(sb, "%s called with no NLS table loaded", __func__);
5231da177e4SLinus Torvalds 		return -EINVAL;
5241da177e4SLinus Torvalds 	}
5251da177e4SLinus Torvalds 
5261da177e4SLinus Torvalds 	*out = result = kmalloc(maxlen, GFP_NOFS);
52762b80719SLuis de Bethencourt 	if (!*out)
5281da177e4SLinus Torvalds 		return -ENOMEM;
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 	for (i = o = 0; i < in_len; i += utflen, o += unilen) {
5311da177e4SLinus Torvalds 
5321da177e4SLinus Torvalds 		/* convert from UTF-8 to Unicode */
53374675a58SAlan Stern 		utflen = utf8_to_utf32(&in[i], in_len - i, &uni);
53474675a58SAlan Stern 		if (utflen < 0)
5351da177e4SLinus Torvalds 			goto conv_err;
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds 		/* convert from Unicode to nls */
53874675a58SAlan Stern 		if (uni > MAX_WCHAR_T)
5391da177e4SLinus Torvalds 			goto conv_err;
54074675a58SAlan Stern 		unilen = nls->uni2char(uni, &result[o], in_len - o);
54174675a58SAlan Stern 		if (unilen < 0)
54274675a58SAlan Stern 			goto conv_err;
5431da177e4SLinus Torvalds 	}
5441da177e4SLinus Torvalds 	result[o] = '\0';
5451da177e4SLinus Torvalds 	*out_len = o;
5461da177e4SLinus Torvalds 
547dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
5481da177e4SLinus Torvalds 
5491da177e4SLinus Torvalds 	return o;
5501da177e4SLinus Torvalds 
5511da177e4SLinus Torvalds conv_err:
5521da177e4SLinus Torvalds 	befs_error(sb, "Name using character set %s contains a character that "
5531da177e4SLinus Torvalds 		   "cannot be converted to unicode.", nls->charset);
554dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
5551da177e4SLinus Torvalds 	kfree(result);
5561da177e4SLinus Torvalds 	return -EILSEQ;
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds /**
5601da177e4SLinus Torvalds  * befs_nls2utf - Convert NLS string to utf8 encodeing
5611da177e4SLinus Torvalds  * @sb: Superblock
562817e1d90SFabian Frederick  * @in: Input string buffer in NLS format
563817e1d90SFabian Frederick  * @in_len: Length of input string in bytes
564817e1d90SFabian Frederick  * @out: The output string in UTF-8 format
565817e1d90SFabian Frederick  * @out_len: Length of the output buffer
5661da177e4SLinus Torvalds  *
567817e1d90SFabian Frederick  * Converts input string @in, which is in the format of the loaded NLS map,
5681da177e4SLinus Torvalds  * into a utf8 string.
5691da177e4SLinus Torvalds  *
570817e1d90SFabian Frederick  * The destination string @out is allocated by this function and the caller is
5711da177e4SLinus Torvalds  * responsible for freeing it with kfree()
5721da177e4SLinus Torvalds  *
573817e1d90SFabian Frederick  * On return, *@out_len is the length of @out in bytes.
5741da177e4SLinus Torvalds  *
5751da177e4SLinus Torvalds  * On success, the return value is the number of utf8 characters written to
576817e1d90SFabian Frederick  * the output buffer @out.
5771da177e4SLinus Torvalds  *
5781da177e4SLinus Torvalds  * On Failure, a negative number coresponding to the error code is returned.
5791da177e4SLinus Torvalds  */
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds static int
befs_nls2utf(struct super_block * sb,const char * in,int in_len,char ** out,int * out_len)5821da177e4SLinus Torvalds befs_nls2utf(struct super_block *sb, const char *in,
5831da177e4SLinus Torvalds 	     int in_len, char **out, int *out_len)
5841da177e4SLinus Torvalds {
5851da177e4SLinus Torvalds 	struct nls_table *nls = BEFS_SB(sb)->nls;
5861da177e4SLinus Torvalds 	int i, o;
5871da177e4SLinus Torvalds 	wchar_t uni;
5881da177e4SLinus Torvalds 	int unilen, utflen;
5891da177e4SLinus Torvalds 	char *result;
5901ca7087eSLuis de Bethencourt 	/*
5911ca7087eSLuis de Bethencourt 	 * There are nls characters that will translate to 3-chars-wide UTF-8
5921ca7087eSLuis de Bethencourt 	 * characters, an additional byte is needed to save the final \0
59362b80719SLuis de Bethencourt 	 * in special cases
59462b80719SLuis de Bethencourt 	 */
59594f563c4SDiego Calleja 	int maxlen = (3 * in_len) + 1;
5961da177e4SLinus Torvalds 
597dac52fc1SFabian Frederick 	befs_debug(sb, "---> %s\n", __func__);
5981da177e4SLinus Torvalds 
5991da177e4SLinus Torvalds 	if (!nls) {
600dac52fc1SFabian Frederick 		befs_error(sb, "%s called with no NLS table loaded.",
601dac52fc1SFabian Frederick 			   __func__);
6021da177e4SLinus Torvalds 		return -EINVAL;
6031da177e4SLinus Torvalds 	}
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 	*out = result = kmalloc(maxlen, GFP_NOFS);
6061da177e4SLinus Torvalds 	if (!*out) {
6071da177e4SLinus Torvalds 		*out_len = 0;
6081da177e4SLinus Torvalds 		return -ENOMEM;
6091da177e4SLinus Torvalds 	}
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds 	for (i = o = 0; i < in_len; i += unilen, o += utflen) {
6121da177e4SLinus Torvalds 
6131da177e4SLinus Torvalds 		/* convert from nls to unicode */
6141da177e4SLinus Torvalds 		unilen = nls->char2uni(&in[i], in_len - i, &uni);
61574675a58SAlan Stern 		if (unilen < 0)
6161da177e4SLinus Torvalds 			goto conv_err;
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds 		/* convert from unicode to UTF-8 */
61974675a58SAlan Stern 		utflen = utf32_to_utf8(uni, &result[o], 3);
62074675a58SAlan Stern 		if (utflen <= 0)
6211da177e4SLinus Torvalds 			goto conv_err;
6221da177e4SLinus Torvalds 	}
6231da177e4SLinus Torvalds 
6241da177e4SLinus Torvalds 	result[o] = '\0';
6251da177e4SLinus Torvalds 	*out_len = o;
6261da177e4SLinus Torvalds 
627dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	return i;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds conv_err:
6321ca7087eSLuis de Bethencourt 	befs_error(sb, "Name using character set %s contains a character that "
6331da177e4SLinus Torvalds 		   "cannot be converted to unicode.", nls->charset);
634dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
6351da177e4SLinus Torvalds 	kfree(result);
6361da177e4SLinus Torvalds 	return -EILSEQ;
6371da177e4SLinus Torvalds }
6381da177e4SLinus Torvalds 
befs_nfs_get_inode(struct super_block * sb,uint64_t ino,uint32_t generation)639ac632f5bSLuis de Bethencourt static struct inode *befs_nfs_get_inode(struct super_block *sb, uint64_t ino,
640ac632f5bSLuis de Bethencourt 					 uint32_t generation)
641ac632f5bSLuis de Bethencourt {
642ac632f5bSLuis de Bethencourt 	/* No need to handle i_generation */
643ac632f5bSLuis de Bethencourt 	return befs_iget(sb, ino);
644ac632f5bSLuis de Bethencourt }
645ac632f5bSLuis de Bethencourt 
646ac632f5bSLuis de Bethencourt /*
647ac632f5bSLuis de Bethencourt  * Map a NFS file handle to a corresponding dentry
648ac632f5bSLuis de Bethencourt  */
befs_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)649ac632f5bSLuis de Bethencourt static struct dentry *befs_fh_to_dentry(struct super_block *sb,
650ac632f5bSLuis de Bethencourt 				struct fid *fid, int fh_len, int fh_type)
651ac632f5bSLuis de Bethencourt {
652ac632f5bSLuis de Bethencourt 	return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
653ac632f5bSLuis de Bethencourt 				    befs_nfs_get_inode);
654ac632f5bSLuis de Bethencourt }
655ac632f5bSLuis de Bethencourt 
656ac632f5bSLuis de Bethencourt /*
657ac632f5bSLuis de Bethencourt  * Find the parent for a file specified by NFS handle
658ac632f5bSLuis de Bethencourt  */
befs_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)659ac632f5bSLuis de Bethencourt static struct dentry *befs_fh_to_parent(struct super_block *sb,
660ac632f5bSLuis de Bethencourt 				struct fid *fid, int fh_len, int fh_type)
661ac632f5bSLuis de Bethencourt {
662ac632f5bSLuis de Bethencourt 	return generic_fh_to_parent(sb, fid, fh_len, fh_type,
663ac632f5bSLuis de Bethencourt 				    befs_nfs_get_inode);
664ac632f5bSLuis de Bethencourt }
665ac632f5bSLuis de Bethencourt 
befs_get_parent(struct dentry * child)666dcfd9b21SFabian Frederick static struct dentry *befs_get_parent(struct dentry *child)
667dcfd9b21SFabian Frederick {
668dcfd9b21SFabian Frederick 	struct inode *parent;
669dcfd9b21SFabian Frederick 	struct befs_inode_info *befs_ino = BEFS_I(d_inode(child));
670dcfd9b21SFabian Frederick 
671dcfd9b21SFabian Frederick 	parent = befs_iget(child->d_sb,
672dcfd9b21SFabian Frederick 			   (unsigned long)befs_ino->i_parent.start);
673dcfd9b21SFabian Frederick 	if (IS_ERR(parent))
674dcfd9b21SFabian Frederick 		return ERR_CAST(parent);
675dcfd9b21SFabian Frederick 
676dcfd9b21SFabian Frederick 	return d_obtain_alias(parent);
677dcfd9b21SFabian Frederick }
678dcfd9b21SFabian Frederick 
6791da177e4SLinus Torvalds enum {
6801da177e4SLinus Torvalds 	Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err,
6811da177e4SLinus Torvalds };
6821da177e4SLinus Torvalds 
683a447c093SSteven Whitehouse static const match_table_t befs_tokens = {
6841da177e4SLinus Torvalds 	{Opt_uid, "uid=%d"},
6851da177e4SLinus Torvalds 	{Opt_gid, "gid=%d"},
6861da177e4SLinus Torvalds 	{Opt_charset, "iocharset=%s"},
6871da177e4SLinus Torvalds 	{Opt_debug, "debug"},
6881da177e4SLinus Torvalds 	{Opt_err, NULL}
6891da177e4SLinus Torvalds };
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds static int
parse_options(char * options,struct befs_mount_options * opts)69209ad0eaeSFabian Frederick parse_options(char *options, struct befs_mount_options *opts)
6931da177e4SLinus Torvalds {
6941da177e4SLinus Torvalds 	char *p;
6951da177e4SLinus Torvalds 	substring_t args[MAX_OPT_ARGS];
6961da177e4SLinus Torvalds 	int option;
69731aba059SEric W. Biederman 	kuid_t uid;
69831aba059SEric W. Biederman 	kgid_t gid;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	/* Initialize options */
70131aba059SEric W. Biederman 	opts->uid = GLOBAL_ROOT_UID;
70231aba059SEric W. Biederman 	opts->gid = GLOBAL_ROOT_GID;
7031da177e4SLinus Torvalds 	opts->use_uid = 0;
7041da177e4SLinus Torvalds 	opts->use_gid = 0;
7051da177e4SLinus Torvalds 	opts->iocharset = NULL;
7061da177e4SLinus Torvalds 	opts->debug = 0;
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 	if (!options)
7091da177e4SLinus Torvalds 		return 1;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	while ((p = strsep(&options, ",")) != NULL) {
7121da177e4SLinus Torvalds 		int token;
71362b80719SLuis de Bethencourt 
7141da177e4SLinus Torvalds 		if (!*p)
7151da177e4SLinus Torvalds 			continue;
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 		token = match_token(p, befs_tokens, args);
7181da177e4SLinus Torvalds 		switch (token) {
7191da177e4SLinus Torvalds 		case Opt_uid:
7201da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
7211da177e4SLinus Torvalds 				return 0;
72231aba059SEric W. Biederman 			uid = INVALID_UID;
72331aba059SEric W. Biederman 			if (option >= 0)
72431aba059SEric W. Biederman 				uid = make_kuid(current_user_ns(), option);
72531aba059SEric W. Biederman 			if (!uid_valid(uid)) {
726dac52fc1SFabian Frederick 				pr_err("Invalid uid %d, "
7271da177e4SLinus Torvalds 				       "using default\n", option);
7281da177e4SLinus Torvalds 				break;
7291da177e4SLinus Torvalds 			}
73031aba059SEric W. Biederman 			opts->uid = uid;
7311da177e4SLinus Torvalds 			opts->use_uid = 1;
7321da177e4SLinus Torvalds 			break;
7331da177e4SLinus Torvalds 		case Opt_gid:
7341da177e4SLinus Torvalds 			if (match_int(&args[0], &option))
7351da177e4SLinus Torvalds 				return 0;
73631aba059SEric W. Biederman 			gid = INVALID_GID;
73731aba059SEric W. Biederman 			if (option >= 0)
73831aba059SEric W. Biederman 				gid = make_kgid(current_user_ns(), option);
73931aba059SEric W. Biederman 			if (!gid_valid(gid)) {
740dac52fc1SFabian Frederick 				pr_err("Invalid gid %d, "
7411da177e4SLinus Torvalds 				       "using default\n", option);
7421da177e4SLinus Torvalds 				break;
7431da177e4SLinus Torvalds 			}
74431aba059SEric W. Biederman 			opts->gid = gid;
7451da177e4SLinus Torvalds 			opts->use_gid = 1;
7461da177e4SLinus Torvalds 			break;
7471da177e4SLinus Torvalds 		case Opt_charset:
7481da177e4SLinus Torvalds 			kfree(opts->iocharset);
7491da177e4SLinus Torvalds 			opts->iocharset = match_strdup(&args[0]);
7501da177e4SLinus Torvalds 			if (!opts->iocharset) {
751dac52fc1SFabian Frederick 				pr_err("allocation failure for "
7521da177e4SLinus Torvalds 				       "iocharset string\n");
7531da177e4SLinus Torvalds 				return 0;
7541da177e4SLinus Torvalds 			}
7551da177e4SLinus Torvalds 			break;
7561da177e4SLinus Torvalds 		case Opt_debug:
7571da177e4SLinus Torvalds 			opts->debug = 1;
7581da177e4SLinus Torvalds 			break;
7591da177e4SLinus Torvalds 		default:
760dac52fc1SFabian Frederick 			pr_err("Unrecognized mount option \"%s\" "
7611da177e4SLinus Torvalds 			       "or missing value\n", p);
7621da177e4SLinus Torvalds 			return 0;
7631da177e4SLinus Torvalds 		}
7641da177e4SLinus Torvalds 	}
7651da177e4SLinus Torvalds 	return 1;
7661da177e4SLinus Torvalds }
7671da177e4SLinus Torvalds 
befs_show_options(struct seq_file * m,struct dentry * root)7683ab7947aSDavid Howells static int befs_show_options(struct seq_file *m, struct dentry *root)
7693ab7947aSDavid Howells {
7703ab7947aSDavid Howells 	struct befs_sb_info *befs_sb = BEFS_SB(root->d_sb);
7713ab7947aSDavid Howells 	struct befs_mount_options *opts = &befs_sb->mount_opts;
7723ab7947aSDavid Howells 
7733ab7947aSDavid Howells 	if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
7743ab7947aSDavid Howells 		seq_printf(m, ",uid=%u",
7753ab7947aSDavid Howells 			   from_kuid_munged(&init_user_ns, opts->uid));
7763ab7947aSDavid Howells 	if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
7773ab7947aSDavid Howells 		seq_printf(m, ",gid=%u",
7783ab7947aSDavid Howells 			   from_kgid_munged(&init_user_ns, opts->gid));
7793ab7947aSDavid Howells 	if (opts->iocharset)
7803ab7947aSDavid Howells 		seq_printf(m, ",charset=%s", opts->iocharset);
7813ab7947aSDavid Howells 	if (opts->debug)
7823ab7947aSDavid Howells 		seq_puts(m, ",debug");
7833ab7947aSDavid Howells 	return 0;
7843ab7947aSDavid Howells }
7853ab7947aSDavid Howells 
7861da177e4SLinus Torvalds /* This function has the responsibiltiy of getting the
7871da177e4SLinus Torvalds  * filesystem ready for unmounting.
78825985edcSLucas De Marchi  * Basically, we free everything that we allocated in
7891da177e4SLinus Torvalds  * befs_read_inode
7901da177e4SLinus Torvalds  */
7911da177e4SLinus Torvalds static void
befs_put_super(struct super_block * sb)7921da177e4SLinus Torvalds befs_put_super(struct super_block *sb)
7931da177e4SLinus Torvalds {
7941da177e4SLinus Torvalds 	kfree(BEFS_SB(sb)->mount_opts.iocharset);
7951da177e4SLinus Torvalds 	BEFS_SB(sb)->mount_opts.iocharset = NULL;
7961da177e4SLinus Torvalds 	unload_nls(BEFS_SB(sb)->nls);
7971da177e4SLinus Torvalds 	kfree(sb->s_fs_info);
7981da177e4SLinus Torvalds 	sb->s_fs_info = NULL;
7991da177e4SLinus Torvalds }
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds /* Allocate private field of the superblock, fill it.
8021da177e4SLinus Torvalds  *
8031da177e4SLinus Torvalds  * Finish filling the public superblock fields
8041da177e4SLinus Torvalds  * Make the root directory
8051da177e4SLinus Torvalds  * Load a set of NLS translations if needed.
8061da177e4SLinus Torvalds  */
8071da177e4SLinus Torvalds static int
befs_fill_super(struct super_block * sb,void * data,int silent)8081da177e4SLinus Torvalds befs_fill_super(struct super_block *sb, void *data, int silent)
8091da177e4SLinus Torvalds {
8101da177e4SLinus Torvalds 	struct buffer_head *bh;
811038428fcSFabian Frederick 	struct befs_sb_info *befs_sb;
8121da177e4SLinus Torvalds 	befs_super_block *disk_sb;
8131da177e4SLinus Torvalds 	struct inode *root;
81496eb5419SDavid Howells 	long ret = -EINVAL;
8151da177e4SLinus Torvalds 	const unsigned long sb_block = 0;
8161da177e4SLinus Torvalds 	const off_t x86_sb_off = 512;
817173b066fSLuis de Bethencourt 	int blocksize;
8181da177e4SLinus Torvalds 
8192d4319efSFabian Frederick 	sb->s_fs_info = kzalloc(sizeof(*befs_sb), GFP_KERNEL);
820c625426fSSalah Triki 	if (sb->s_fs_info == NULL)
8210418726bSAdrian Bunk 		goto unacquire_none;
822c625426fSSalah Triki 
8231da177e4SLinus Torvalds 	befs_sb = BEFS_SB(sb);
8241da177e4SLinus Torvalds 
8251da177e4SLinus Torvalds 	if (!parse_options((char *) data, &befs_sb->mount_opts)) {
826dceee2e2SSalah Triki 		if (!silent)
8271da177e4SLinus Torvalds 			befs_error(sb, "cannot parse mount options");
8280418726bSAdrian Bunk 		goto unacquire_priv_sbp;
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds 
831dac52fc1SFabian Frederick 	befs_debug(sb, "---> %s", __func__);
8321da177e4SLinus Torvalds 
833bc98a42cSDavid Howells 	if (!sb_rdonly(sb)) {
8341da177e4SLinus Torvalds 		befs_warning(sb,
8351da177e4SLinus Torvalds 			     "No write support. Marking filesystem read-only");
8361751e8a6SLinus Torvalds 		sb->s_flags |= SB_RDONLY;
8371da177e4SLinus Torvalds 	}
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	/*
8401da177e4SLinus Torvalds 	 * Set dummy blocksize to read super block.
8411da177e4SLinus Torvalds 	 * Will be set to real fs blocksize later.
8421da177e4SLinus Torvalds 	 *
8431da177e4SLinus Torvalds 	 * Linux 2.4.10 and later refuse to read blocks smaller than
844a441b0d0SLinus Walleij 	 * the logical block size for the device. But we also need to read at
8451da177e4SLinus Torvalds 	 * least 1k to get the second 512 bytes of the volume.
8461da177e4SLinus Torvalds 	 */
847173b066fSLuis de Bethencourt 	blocksize = sb_min_blocksize(sb, 1024);
848173b066fSLuis de Bethencourt 	if (!blocksize) {
849a6499850SLuis de Bethencourt 		if (!silent)
850173b066fSLuis de Bethencourt 			befs_error(sb, "unable to set blocksize");
851173b066fSLuis de Bethencourt 		goto unacquire_priv_sbp;
852173b066fSLuis de Bethencourt 	}
8531da177e4SLinus Torvalds 
85462b80719SLuis de Bethencourt 	bh = sb_bread(sb, sb_block);
85562b80719SLuis de Bethencourt 	if (!bh) {
856dceee2e2SSalah Triki 		if (!silent)
8571da177e4SLinus Torvalds 			befs_error(sb, "unable to read superblock");
8580418726bSAdrian Bunk 		goto unacquire_priv_sbp;
8591da177e4SLinus Torvalds 	}
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 	/* account for offset of super block on x86 */
8621da177e4SLinus Torvalds 	disk_sb = (befs_super_block *) bh->b_data;
863152b95a1SHarvey Harrison 	if ((disk_sb->magic1 == BEFS_SUPER_MAGIC1_LE) ||
864152b95a1SHarvey Harrison 	    (disk_sb->magic1 == BEFS_SUPER_MAGIC1_BE)) {
8651da177e4SLinus Torvalds 		befs_debug(sb, "Using PPC superblock location");
8661da177e4SLinus Torvalds 	} else {
8671da177e4SLinus Torvalds 		befs_debug(sb, "Using x86 superblock location");
8681da177e4SLinus Torvalds 		disk_sb =
8691da177e4SLinus Torvalds 		    (befs_super_block *) ((void *) bh->b_data + x86_sb_off);
8701da177e4SLinus Torvalds 	}
8711da177e4SLinus Torvalds 
8728e19189eSFabian Frederick 	if ((befs_load_sb(sb, disk_sb) != BEFS_OK) ||
8738e19189eSFabian Frederick 	    (befs_check_sb(sb) != BEFS_OK))
8740418726bSAdrian Bunk 		goto unacquire_bh;
8751da177e4SLinus Torvalds 
8761da177e4SLinus Torvalds 	befs_dump_super_block(sb, disk_sb);
8771da177e4SLinus Torvalds 
8781da177e4SLinus Torvalds 	brelse(bh);
8791da177e4SLinus Torvalds 
8801da177e4SLinus Torvalds 	if (befs_sb->num_blocks > ~((sector_t)0)) {
881dceee2e2SSalah Triki 		if (!silent)
882dceee2e2SSalah Triki 			befs_error(sb, "blocks count: %llu is larger than the host can use",
8831da177e4SLinus Torvalds 					befs_sb->num_blocks);
8840418726bSAdrian Bunk 		goto unacquire_priv_sbp;
8851da177e4SLinus Torvalds 	}
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 	/*
8881da177e4SLinus Torvalds 	 * set up enough so that it can read an inode
8891da177e4SLinus Torvalds 	 * Fill in kernel superblock fields from private sb
8901da177e4SLinus Torvalds 	 */
8911da177e4SLinus Torvalds 	sb->s_magic = BEFS_SUPER_MAGIC;
8921da177e4SLinus Torvalds 	/* Set real blocksize of fs */
8931da177e4SLinus Torvalds 	sb_set_blocksize(sb, (ulong) befs_sb->block_size);
894b87221deSAlexey Dobriyan 	sb->s_op = &befs_sops;
895ac632f5bSLuis de Bethencourt 	sb->s_export_op = &befs_export_operations;
89622b13969SDeepa Dinamani 	sb->s_time_min = 0;
89722b13969SDeepa Dinamani 	sb->s_time_max = 0xffffffffffffll;
89896eb5419SDavid Howells 	root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
89996eb5419SDavid Howells 	if (IS_ERR(root)) {
90096eb5419SDavid Howells 		ret = PTR_ERR(root);
90196eb5419SDavid Howells 		goto unacquire_priv_sbp;
90296eb5419SDavid Howells 	}
90348fde701SAl Viro 	sb->s_root = d_make_root(root);
9041da177e4SLinus Torvalds 	if (!sb->s_root) {
905dceee2e2SSalah Triki 		if (!silent)
9061da177e4SLinus Torvalds 			befs_error(sb, "get root inode failed");
9070418726bSAdrian Bunk 		goto unacquire_priv_sbp;
9081da177e4SLinus Torvalds 	}
9091da177e4SLinus Torvalds 
9101da177e4SLinus Torvalds 	/* load nls library */
9111da177e4SLinus Torvalds 	if (befs_sb->mount_opts.iocharset) {
9121da177e4SLinus Torvalds 		befs_debug(sb, "Loading nls: %s",
9131da177e4SLinus Torvalds 			   befs_sb->mount_opts.iocharset);
9141da177e4SLinus Torvalds 		befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset);
9151da177e4SLinus Torvalds 		if (!befs_sb->nls) {
9161da177e4SLinus Torvalds 			befs_warning(sb, "Cannot load nls %s"
9171da177e4SLinus Torvalds 					" loading default nls",
9181da177e4SLinus Torvalds 					befs_sb->mount_opts.iocharset);
9191da177e4SLinus Torvalds 			befs_sb->nls = load_nls_default();
9201da177e4SLinus Torvalds 		}
9211da177e4SLinus Torvalds 	/* load default nls if none is specified  in mount options */
9221da177e4SLinus Torvalds 	} else {
9231da177e4SLinus Torvalds 		befs_debug(sb, "Loading default nls");
9241da177e4SLinus Torvalds 		befs_sb->nls = load_nls_default();
9251da177e4SLinus Torvalds 	}
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 	return 0;
92862b80719SLuis de Bethencourt 
9290418726bSAdrian Bunk unacquire_bh:
9301da177e4SLinus Torvalds 	brelse(bh);
9311da177e4SLinus Torvalds 
9320418726bSAdrian Bunk unacquire_priv_sbp:
9338dd5ca53SAl Viro 	kfree(befs_sb->mount_opts.iocharset);
9341da177e4SLinus Torvalds 	kfree(sb->s_fs_info);
93530982583SSalah Triki 	sb->s_fs_info = NULL;
9361da177e4SLinus Torvalds 
9370418726bSAdrian Bunk unacquire_none:
93896eb5419SDavid Howells 	return ret;
9391da177e4SLinus Torvalds }
9401da177e4SLinus Torvalds 
9411da177e4SLinus Torvalds static int
befs_remount(struct super_block * sb,int * flags,char * data)9421da177e4SLinus Torvalds befs_remount(struct super_block *sb, int *flags, char *data)
9431da177e4SLinus Torvalds {
94402b9984dSTheodore Ts'o 	sync_filesystem(sb);
9451751e8a6SLinus Torvalds 	if (!(*flags & SB_RDONLY))
9461da177e4SLinus Torvalds 		return -EINVAL;
9471da177e4SLinus Torvalds 	return 0;
9481da177e4SLinus Torvalds }
9491da177e4SLinus Torvalds 
9501da177e4SLinus Torvalds static int
befs_statfs(struct dentry * dentry,struct kstatfs * buf)951726c3342SDavid Howells befs_statfs(struct dentry *dentry, struct kstatfs *buf)
9521da177e4SLinus Torvalds {
953726c3342SDavid Howells 	struct super_block *sb = dentry->d_sb;
9548587246aSColy Li 	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
9551da177e4SLinus Torvalds 
956dac52fc1SFabian Frederick 	befs_debug(sb, "---> %s", __func__);
9571da177e4SLinus Torvalds 
9581da177e4SLinus Torvalds 	buf->f_type = BEFS_SUPER_MAGIC;
9591da177e4SLinus Torvalds 	buf->f_bsize = sb->s_blocksize;
9601da177e4SLinus Torvalds 	buf->f_blocks = BEFS_SB(sb)->num_blocks;
9611da177e4SLinus Torvalds 	buf->f_bfree = BEFS_SB(sb)->num_blocks - BEFS_SB(sb)->used_blocks;
9621da177e4SLinus Torvalds 	buf->f_bavail = buf->f_bfree;
9631da177e4SLinus Torvalds 	buf->f_files = 0;	/* UNKNOWN */
9641da177e4SLinus Torvalds 	buf->f_ffree = 0;	/* UNKNOWN */
9656d1349c7SAl Viro 	buf->f_fsid = u64_to_fsid(id);
9661da177e4SLinus Torvalds 	buf->f_namelen = BEFS_NAME_LEN;
9671da177e4SLinus Torvalds 
968dac52fc1SFabian Frederick 	befs_debug(sb, "<--- %s", __func__);
9691da177e4SLinus Torvalds 
9701da177e4SLinus Torvalds 	return 0;
9711da177e4SLinus Torvalds }
9721da177e4SLinus Torvalds 
973152a0836SAl Viro static struct dentry *
befs_mount(struct file_system_type * fs_type,int flags,const char * dev_name,void * data)974152a0836SAl Viro befs_mount(struct file_system_type *fs_type, int flags, const char *dev_name,
975152a0836SAl Viro 	    void *data)
9761da177e4SLinus Torvalds {
977152a0836SAl Viro 	return mount_bdev(fs_type, flags, dev_name, data, befs_fill_super);
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds static struct file_system_type befs_fs_type = {
9811da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
9821da177e4SLinus Torvalds 	.name		= "befs",
983152a0836SAl Viro 	.mount		= befs_mount,
9841da177e4SLinus Torvalds 	.kill_sb	= kill_block_super,
9851da177e4SLinus Torvalds 	.fs_flags	= FS_REQUIRES_DEV,
9861da177e4SLinus Torvalds };
9877f78e035SEric W. Biederman MODULE_ALIAS_FS("befs");
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds static int __init
init_befs_fs(void)9901da177e4SLinus Torvalds init_befs_fs(void)
9911da177e4SLinus Torvalds {
9921da177e4SLinus Torvalds 	int err;
9931da177e4SLinus Torvalds 
994dac52fc1SFabian Frederick 	pr_info("version: %s\n", BEFS_VERSION);
9951da177e4SLinus Torvalds 
9961da177e4SLinus Torvalds 	err = befs_init_inodecache();
9971da177e4SLinus Torvalds 	if (err)
9980418726bSAdrian Bunk 		goto unacquire_none;
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 	err = register_filesystem(&befs_fs_type);
10011da177e4SLinus Torvalds 	if (err)
10020418726bSAdrian Bunk 		goto unacquire_inodecache;
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 	return 0;
10051da177e4SLinus Torvalds 
10060418726bSAdrian Bunk unacquire_inodecache:
10071da177e4SLinus Torvalds 	befs_destroy_inodecache();
10081da177e4SLinus Torvalds 
10090418726bSAdrian Bunk unacquire_none:
10101da177e4SLinus Torvalds 	return err;
10111da177e4SLinus Torvalds }
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds static void __exit
exit_befs_fs(void)10141da177e4SLinus Torvalds exit_befs_fs(void)
10151da177e4SLinus Torvalds {
10161da177e4SLinus Torvalds 	befs_destroy_inodecache();
10171da177e4SLinus Torvalds 
10181da177e4SLinus Torvalds 	unregister_filesystem(&befs_fs_type);
10191da177e4SLinus Torvalds }
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds /*
102262b80719SLuis de Bethencourt  * Macros that typecheck the init and exit functions,
102362b80719SLuis de Bethencourt  * ensures that they are called at init and cleanup,
102462b80719SLuis de Bethencourt  * and eliminates warnings about unused functions.
10251da177e4SLinus Torvalds  */
10261da177e4SLinus Torvalds module_init(init_befs_fs)
10271da177e4SLinus Torvalds module_exit(exit_befs_fs)
1028