/* * Called by generic_file_read() to read a folio of data * * In turn, simply calls a generic block read function and * passes it the address of befs_get_block, for mapping file * positions to disk blocks.
*/ staticint befs_read_folio(struct file *file, struct folio *folio)
{ return block_read_full_folio(folio, befs_get_block);
}
/* * Generic function to map a file position (block) to a * disk offset (passed back in bh_result). * * Used by many higher level functions. * * Calls befs_fblock2brun() in datastream.c to do the real work.
*/
staticint
befs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
{ struct super_block *sb = inode->i_sb;
befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
befs_block_run run = BAD_IADDR; int res;
ulong disk_off;
befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld",
(unsignedlong)inode->i_ino, (long)block); if (create) {
befs_error(sb, "befs_get_block() was asked to write to " "block %ld in inode %lu", (long)block,
(unsignedlong)inode->i_ino); return -EPERM;
}
res = befs_fblock2brun(sb, ds, block, &run); if (res != BEFS_OK) {
befs_error(sb, "<--- %s for inode %lu, block %ld ERROR",
__func__, (unsignedlong)inode->i_ino,
(long)block); return -EFBIG;
}
disk_off = (ulong) iaddr2blockno(sb, &run);
map_bh(bh_result, inode->i_sb, disk_off);
befs_debug(sb, "<--- %s for inode %lu, block %ld, disk address %lu",
__func__, (unsignedlong)inode->i_ino, (long)block,
(unsignedlong)disk_off);
/* * BEFS's time is 64 bits, but current VFS is 32 bits... * BEFS don't have access time. Nor inode change time. VFS * doesn't have creation time. * Also, the lower 16 bits of the last_modified_time and * create_time are just a counter to help ensure uniqueness * for indexing purposes. (PFD, page 54)
*/
inode_set_mtime(inode,
fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16,
0);/* lower 16 bits are not a time */
inode_set_ctime_to_ts(inode, inode_get_mtime(inode));
inode_set_atime_to_ts(inode, inode_get_mtime(inode));
/* Initialize the inode cache. Called at fs setup. * * Taken from NFS implementation by Al Viro.
*/ staticint __init
befs_init_inodecache(void)
{
befs_inode_cachep = kmem_cache_create_usercopy("befs_inode_cache", sizeof(struct befs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT | SLAB_ACCOUNT,
offsetof(struct befs_inode_info,
i_data.symlink),
sizeof_field(struct befs_inode_info,
i_data.symlink),
init_once); if (befs_inode_cachep == NULL) return -ENOMEM;
return 0;
}
/* Called at fs teardown. * * Taken from NFS implementation by Al Viro.
*/ staticvoid
befs_destroy_inodecache(void)
{ /* * Make sure all delayed rcu free inodes are flushed before we * destroy cache.
*/
rcu_barrier();
kmem_cache_destroy(befs_inode_cachep);
}
/* * The inode of symbolic link is different to data stream. * The data stream become link name. Unless the LONG_SYMLINK * flag is set.
*/ staticint befs_symlink_read_folio(struct file *unused, struct folio *folio)
{ struct inode *inode = folio->mapping->host; struct super_block *sb = inode->i_sb; struct befs_inode_info *befs_ino = BEFS_I(inode);
befs_data_stream *data = &befs_ino->i_data.ds;
befs_off_t len = data->size; char *link = folio_address(folio); int err = -EIO;
if (len == 0 || len > PAGE_SIZE) {
befs_error(sb, "Long symlink with illegal length"); goto fail;
}
befs_debug(sb, "Follow long symlink");
/* * UTF-8 to NLS charset convert routine * * Uses uni2char() / char2uni() rather than the nls tables directly
*/ staticint
befs_utf2nls(struct super_block *sb, constchar *in, int in_len, char **out, int *out_len)
{ struct nls_table *nls = BEFS_SB(sb)->nls; int i, o;
unicode_t uni; int unilen, utflen; char *result; /* The utf8->nls conversion won't make the final nls string bigger * than the utf one, but if the string is pure ascii they'll have the * same width and an extra char is needed to save the additional \0
*/ int maxlen = in_len + 1;
befs_debug(sb, "---> %s", __func__);
if (!nls) {
befs_error(sb, "%s called with no NLS table loaded", __func__); return -EINVAL;
}
*out = result = kmalloc(maxlen, GFP_NOFS); if (!*out) return -ENOMEM;
for (i = o = 0; i < in_len; i += utflen, o += unilen) {
/* convert from UTF-8 to Unicode */
utflen = utf8_to_utf32(&in[i], in_len - i, &uni); if (utflen < 0) goto conv_err;
/* convert from Unicode to nls */ if (uni > MAX_WCHAR_T) goto conv_err;
unilen = nls->uni2char(uni, &result[o], in_len - o); if (unilen < 0) goto conv_err;
}
result[o] = '\0';
*out_len = o;
befs_debug(sb, "<--- %s", __func__);
return o;
conv_err:
befs_error(sb, "Name using character set %s contains a character that " "cannot be converted to unicode.", nls->charset);
befs_debug(sb, "<--- %s", __func__);
kfree(result); return -EILSEQ;
}
/** * befs_nls2utf - Convert NLS string to utf8 encodeing * @sb: Superblock * @in: Input string buffer in NLS format * @in_len: Length of input string in bytes * @out: The output string in UTF-8 format * @out_len: Length of the output buffer * * Converts input string @in, which is in the format of the loaded NLS map, * into a utf8 string. * * The destination string @out is allocated by this function and the caller is * responsible for freeing it with kfree() * * On return, *@out_len is the length of @out in bytes. * * On success, the return value is the number of utf8 characters written to * the output buffer @out. * * On Failure, a negative number coresponding to the error code is returned.
*/
staticint
befs_nls2utf(struct super_block *sb, constchar *in, int in_len, char **out, int *out_len)
{ struct nls_table *nls = BEFS_SB(sb)->nls; int i, o; wchar_t uni; int unilen, utflen; char *result; /* * There are nls characters that will translate to 3-chars-wide UTF-8 * characters, an additional byte is needed to save the final \0 * in special cases
*/ int maxlen = (3 * in_len) + 1;
befs_debug(sb, "---> %s\n", __func__);
if (!nls) {
befs_error(sb, "%s called with no NLS table loaded.",
__func__); return -EINVAL;
}
*out = result = kmalloc(maxlen, GFP_NOFS); if (!*out) {
*out_len = 0; return -ENOMEM;
}
for (i = o = 0; i < in_len; i += unilen, o += utflen) {
/* convert from nls to unicode */
unilen = nls->char2uni(&in[i], in_len - i, &uni); if (unilen < 0) goto conv_err;
/* convert from unicode to UTF-8 */
utflen = utf32_to_utf8(uni, &result[o], 3); if (utflen <= 0) goto conv_err;
}
result[o] = '\0';
*out_len = o;
befs_debug(sb, "<--- %s", __func__);
return i;
conv_err:
befs_error(sb, "Name using character set %s contains a character that " "cannot be converted to unicode.", nls->charset);
befs_debug(sb, "<--- %s", __func__);
kfree(result); return -EILSEQ;
}
staticstruct inode *befs_nfs_get_inode(struct super_block *sb, uint64_t ino,
uint32_t generation)
{ /* No need to handle i_generation */ return befs_iget(sb, ino);
}
/* * Map a NFS file handle to a corresponding dentry
*/ staticstruct dentry *befs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
{ return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
befs_nfs_get_inode);
}
/* * Find the parent for a file specified by NFS handle
*/ staticstruct dentry *befs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
{ return generic_fh_to_parent(sb, fid, fh_len, fh_type,
befs_nfs_get_inode);
}
if (!uid_eq(opts->uid, GLOBAL_ROOT_UID))
seq_printf(m, ",uid=%u",
from_kuid_munged(&init_user_ns, opts->uid)); if (!gid_eq(opts->gid, GLOBAL_ROOT_GID))
seq_printf(m, ",gid=%u",
from_kgid_munged(&init_user_ns, opts->gid)); if (opts->iocharset)
seq_printf(m, ",charset=%s", opts->iocharset); if (opts->debug)
seq_puts(m, ",debug"); return 0;
}
/* This function has the responsibiltiy of getting the * filesystem ready for unmounting. * Basically, we free everything that we allocated in * befs_read_inode
*/ staticvoid
befs_put_super(struct super_block *sb)
{
kfree(BEFS_SB(sb)->mount_opts.iocharset);
BEFS_SB(sb)->mount_opts.iocharset = NULL;
unload_nls(BEFS_SB(sb)->nls);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
}
/* Allocate private field of the superblock, fill it. * * Finish filling the public superblock fields * Make the root directory * Load a set of NLS translations if needed.
*/ staticint
befs_fill_super(struct super_block *sb, struct fs_context *fc)
{ struct buffer_head *bh; struct befs_sb_info *befs_sb;
befs_super_block *disk_sb; struct inode *root; long ret = -EINVAL; constunsignedlong sb_block = 0; const off_t x86_sb_off = 512; int blocksize; struct befs_mount_options *parsed_opts = fc->fs_private; int silent = fc->sb_flags & SB_SILENT;
sb->s_fs_info = kzalloc(sizeof(*befs_sb), GFP_KERNEL); if (sb->s_fs_info == NULL) goto unacquire_none;
befs_sb = BEFS_SB(sb);
befs_set_options(befs_sb, parsed_opts);
befs_debug(sb, "---> %s", __func__);
if (!sb_rdonly(sb)) {
befs_warning(sb, "No write support. Marking filesystem read-only");
sb->s_flags |= SB_RDONLY;
}
/* * Set dummy blocksize to read super block. * Will be set to real fs blocksize later. * * Linux 2.4.10 and later refuse to read blocks smaller than * the logical block size for the device. But we also need to read at * least 1k to get the second 512 bytes of the volume.
*/
blocksize = sb_min_blocksize(sb, 1024); if (!blocksize) { if (!silent)
befs_error(sb, "unable to set blocksize"); goto unacquire_priv_sbp;
}
bh = sb_bread(sb, sb_block); if (!bh) { if (!silent)
befs_error(sb, "unable to read superblock"); goto unacquire_priv_sbp;
}
/* account for offset of super block on x86 */
disk_sb = (befs_super_block *) bh->b_data; if ((disk_sb->magic1 == BEFS_SUPER_MAGIC1_LE) ||
(disk_sb->magic1 == BEFS_SUPER_MAGIC1_BE)) {
befs_debug(sb, "Using PPC superblock location");
} else {
befs_debug(sb, "Using x86 superblock location");
disk_sb =
(befs_super_block *) ((void *) bh->b_data + x86_sb_off);
}
if (befs_sb->num_blocks > ~((sector_t)0)) { if (!silent)
befs_error(sb, "blocks count: %llu is larger than the host can use",
befs_sb->num_blocks); goto unacquire_priv_sbp;
}
/* * set up enough so that it can read an inode * Fill in kernel superblock fields from private sb
*/
sb->s_magic = BEFS_SUPER_MAGIC; /* Set real blocksize of fs */
sb_set_blocksize(sb, (ulong) befs_sb->block_size);
sb->s_op = &befs_sops;
sb->s_export_op = &befs_export_operations;
sb->s_time_min = 0;
sb->s_time_max = 0xffffffffffffll;
root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))); if (IS_ERR(root)) {
ret = PTR_ERR(root); goto unacquire_priv_sbp;
}
sb->s_root = d_make_root(root); if (!sb->s_root) { if (!silent)
befs_error(sb, "get root inode failed"); goto unacquire_priv_sbp;
}
/* load nls library */ if (befs_sb->mount_opts.iocharset) {
befs_debug(sb, "Loading nls: %s",
befs_sb->mount_opts.iocharset);
befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset); if (!befs_sb->nls) {
befs_warning(sb, "Cannot load nls %s" " loading default nls",
befs_sb->mount_opts.iocharset);
befs_sb->nls = load_nls_default();
} /* load default nls if none is specified in mount options */
} else {
befs_debug(sb, "Loading default nls");
befs_sb->nls = load_nls_default();
}
/* * Macros that typecheck the init and exit functions, * ensures that they are called at init and cleanup, * and eliminates warnings about unused functions.
*/
module_init(init_befs_fs)
module_exit(exit_befs_fs)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.