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