18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of UBIFS. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём) 88c2ecf20Sopenharmony_ci * Adrian Hunter 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * This file implements UBIFS initialization and VFS superblock operations. Some 138c2ecf20Sopenharmony_ci * initialization stuff which is rather large and complex is placed at 148c2ecf20Sopenharmony_ci * corresponding subsystems, but most of it is here. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/ctype.h> 218c2ecf20Sopenharmony_ci#include <linux/kthread.h> 228c2ecf20Sopenharmony_ci#include <linux/parser.h> 238c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 248c2ecf20Sopenharmony_ci#include <linux/mount.h> 258c2ecf20Sopenharmony_ci#include <linux/math64.h> 268c2ecf20Sopenharmony_ci#include <linux/writeback.h> 278c2ecf20Sopenharmony_ci#include "ubifs.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int ubifs_default_version_set(const char *val, const struct kernel_param *kp) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci int n = 0, ret; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci ret = kstrtoint(val, 10, &n); 348c2ecf20Sopenharmony_ci if (ret != 0 || n < 4 || n > UBIFS_FORMAT_VERSION) 358c2ecf20Sopenharmony_ci return -EINVAL; 368c2ecf20Sopenharmony_ci return param_set_int(val, kp); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic const struct kernel_param_ops ubifs_default_version_ops = { 408c2ecf20Sopenharmony_ci .set = ubifs_default_version_set, 418c2ecf20Sopenharmony_ci .get = param_get_int, 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciint ubifs_default_version = UBIFS_FORMAT_VERSION; 458c2ecf20Sopenharmony_cimodule_param_cb(default_version, &ubifs_default_version_ops, &ubifs_default_version, 0600); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* 488c2ecf20Sopenharmony_ci * Maximum amount of memory we may 'kmalloc()' without worrying that we are 498c2ecf20Sopenharmony_ci * allocating too much. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci#define UBIFS_KMALLOC_OK (128*1024) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* Slab cache for UBIFS inodes */ 548c2ecf20Sopenharmony_cistatic struct kmem_cache *ubifs_inode_slab; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* UBIFS TNC shrinker description */ 578c2ecf20Sopenharmony_cistatic struct shrinker ubifs_shrinker_info = { 588c2ecf20Sopenharmony_ci .scan_objects = ubifs_shrink_scan, 598c2ecf20Sopenharmony_ci .count_objects = ubifs_shrink_count, 608c2ecf20Sopenharmony_ci .seeks = DEFAULT_SEEKS, 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * validate_inode - validate inode. 658c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 668c2ecf20Sopenharmony_ci * @inode: the inode to validate 678c2ecf20Sopenharmony_ci * 688c2ecf20Sopenharmony_ci * This is a helper function for 'ubifs_iget()' which validates various fields 698c2ecf20Sopenharmony_ci * of a newly built inode to make sure they contain sane values and prevent 708c2ecf20Sopenharmony_ci * possible vulnerabilities. Returns zero if the inode is all right and 718c2ecf20Sopenharmony_ci * a non-zero error code if not. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_cistatic int validate_inode(struct ubifs_info *c, const struct inode *inode) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int err; 768c2ecf20Sopenharmony_ci const struct ubifs_inode *ui = ubifs_inode(inode); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (inode->i_size > c->max_inode_sz) { 798c2ecf20Sopenharmony_ci ubifs_err(c, "inode is too large (%lld)", 808c2ecf20Sopenharmony_ci (long long)inode->i_size); 818c2ecf20Sopenharmony_ci return 1; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (ui->compr_type >= UBIFS_COMPR_TYPES_CNT) { 858c2ecf20Sopenharmony_ci ubifs_err(c, "unknown compression type %d", ui->compr_type); 868c2ecf20Sopenharmony_ci return 2; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (ui->xattr_names + ui->xattr_cnt > XATTR_LIST_MAX) 908c2ecf20Sopenharmony_ci return 3; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (ui->data_len < 0 || ui->data_len > UBIFS_MAX_INO_DATA) 938c2ecf20Sopenharmony_ci return 4; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (ui->xattr && !S_ISREG(inode->i_mode)) 968c2ecf20Sopenharmony_ci return 5; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!ubifs_compr_present(c, ui->compr_type)) { 998c2ecf20Sopenharmony_ci ubifs_warn(c, "inode %lu uses '%s' compression, but it was not compiled in", 1008c2ecf20Sopenharmony_ci inode->i_ino, ubifs_compr_name(c, ui->compr_type)); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci err = dbg_check_dir(c, inode); 1048c2ecf20Sopenharmony_ci return err; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistruct inode *ubifs_iget(struct super_block *sb, unsigned long inum) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int err; 1108c2ecf20Sopenharmony_ci union ubifs_key key; 1118c2ecf20Sopenharmony_ci struct ubifs_ino_node *ino; 1128c2ecf20Sopenharmony_ci struct ubifs_info *c = sb->s_fs_info; 1138c2ecf20Sopenharmony_ci struct inode *inode; 1148c2ecf20Sopenharmony_ci struct ubifs_inode *ui; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dbg_gen("inode %lu", inum); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci inode = iget_locked(sb, inum); 1198c2ecf20Sopenharmony_ci if (!inode) 1208c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1218c2ecf20Sopenharmony_ci if (!(inode->i_state & I_NEW)) 1228c2ecf20Sopenharmony_ci return inode; 1238c2ecf20Sopenharmony_ci ui = ubifs_inode(inode); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ino = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS); 1268c2ecf20Sopenharmony_ci if (!ino) { 1278c2ecf20Sopenharmony_ci err = -ENOMEM; 1288c2ecf20Sopenharmony_ci goto out; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci ino_key_init(c, &key, inode->i_ino); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci err = ubifs_tnc_lookup(c, &key, ino); 1348c2ecf20Sopenharmony_ci if (err) 1358c2ecf20Sopenharmony_ci goto out_ino; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci inode->i_flags |= S_NOCMTIME; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT)) 1408c2ecf20Sopenharmony_ci inode->i_flags |= S_NOATIME; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci set_nlink(inode, le32_to_cpu(ino->nlink)); 1438c2ecf20Sopenharmony_ci i_uid_write(inode, le32_to_cpu(ino->uid)); 1448c2ecf20Sopenharmony_ci i_gid_write(inode, le32_to_cpu(ino->gid)); 1458c2ecf20Sopenharmony_ci inode->i_atime.tv_sec = (int64_t)le64_to_cpu(ino->atime_sec); 1468c2ecf20Sopenharmony_ci inode->i_atime.tv_nsec = le32_to_cpu(ino->atime_nsec); 1478c2ecf20Sopenharmony_ci inode->i_mtime.tv_sec = (int64_t)le64_to_cpu(ino->mtime_sec); 1488c2ecf20Sopenharmony_ci inode->i_mtime.tv_nsec = le32_to_cpu(ino->mtime_nsec); 1498c2ecf20Sopenharmony_ci inode->i_ctime.tv_sec = (int64_t)le64_to_cpu(ino->ctime_sec); 1508c2ecf20Sopenharmony_ci inode->i_ctime.tv_nsec = le32_to_cpu(ino->ctime_nsec); 1518c2ecf20Sopenharmony_ci inode->i_mode = le32_to_cpu(ino->mode); 1528c2ecf20Sopenharmony_ci inode->i_size = le64_to_cpu(ino->size); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ui->data_len = le32_to_cpu(ino->data_len); 1558c2ecf20Sopenharmony_ci ui->flags = le32_to_cpu(ino->flags); 1568c2ecf20Sopenharmony_ci ui->compr_type = le16_to_cpu(ino->compr_type); 1578c2ecf20Sopenharmony_ci ui->creat_sqnum = le64_to_cpu(ino->creat_sqnum); 1588c2ecf20Sopenharmony_ci ui->xattr_cnt = le32_to_cpu(ino->xattr_cnt); 1598c2ecf20Sopenharmony_ci ui->xattr_size = le32_to_cpu(ino->xattr_size); 1608c2ecf20Sopenharmony_ci ui->xattr_names = le32_to_cpu(ino->xattr_names); 1618c2ecf20Sopenharmony_ci ui->synced_i_size = ui->ui_size = inode->i_size; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ui->xattr = (ui->flags & UBIFS_XATTR_FL) ? 1 : 0; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci err = validate_inode(c, inode); 1668c2ecf20Sopenharmony_ci if (err) 1678c2ecf20Sopenharmony_ci goto out_invalid; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 1708c2ecf20Sopenharmony_ci case S_IFREG: 1718c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &ubifs_file_address_operations; 1728c2ecf20Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 1738c2ecf20Sopenharmony_ci inode->i_fop = &ubifs_file_operations; 1748c2ecf20Sopenharmony_ci if (ui->xattr) { 1758c2ecf20Sopenharmony_ci ui->data = kmalloc(ui->data_len + 1, GFP_NOFS); 1768c2ecf20Sopenharmony_ci if (!ui->data) { 1778c2ecf20Sopenharmony_ci err = -ENOMEM; 1788c2ecf20Sopenharmony_ci goto out_ino; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci memcpy(ui->data, ino->data, ui->data_len); 1818c2ecf20Sopenharmony_ci ((char *)ui->data)[ui->data_len] = '\0'; 1828c2ecf20Sopenharmony_ci } else if (ui->data_len != 0) { 1838c2ecf20Sopenharmony_ci err = 10; 1848c2ecf20Sopenharmony_ci goto out_invalid; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case S_IFDIR: 1888c2ecf20Sopenharmony_ci inode->i_op = &ubifs_dir_inode_operations; 1898c2ecf20Sopenharmony_ci inode->i_fop = &ubifs_dir_operations; 1908c2ecf20Sopenharmony_ci if (ui->data_len != 0) { 1918c2ecf20Sopenharmony_ci err = 11; 1928c2ecf20Sopenharmony_ci goto out_invalid; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci case S_IFLNK: 1968c2ecf20Sopenharmony_ci inode->i_op = &ubifs_symlink_inode_operations; 1978c2ecf20Sopenharmony_ci if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { 1988c2ecf20Sopenharmony_ci err = 12; 1998c2ecf20Sopenharmony_ci goto out_invalid; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci ui->data = kmalloc(ui->data_len + 1, GFP_NOFS); 2028c2ecf20Sopenharmony_ci if (!ui->data) { 2038c2ecf20Sopenharmony_ci err = -ENOMEM; 2048c2ecf20Sopenharmony_ci goto out_ino; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci memcpy(ui->data, ino->data, ui->data_len); 2078c2ecf20Sopenharmony_ci ((char *)ui->data)[ui->data_len] = '\0'; 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case S_IFBLK: 2108c2ecf20Sopenharmony_ci case S_IFCHR: 2118c2ecf20Sopenharmony_ci { 2128c2ecf20Sopenharmony_ci dev_t rdev; 2138c2ecf20Sopenharmony_ci union ubifs_dev_desc *dev; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); 2168c2ecf20Sopenharmony_ci if (!ui->data) { 2178c2ecf20Sopenharmony_ci err = -ENOMEM; 2188c2ecf20Sopenharmony_ci goto out_ino; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci dev = (union ubifs_dev_desc *)ino->data; 2228c2ecf20Sopenharmony_ci if (ui->data_len == sizeof(dev->new)) 2238c2ecf20Sopenharmony_ci rdev = new_decode_dev(le32_to_cpu(dev->new)); 2248c2ecf20Sopenharmony_ci else if (ui->data_len == sizeof(dev->huge)) 2258c2ecf20Sopenharmony_ci rdev = huge_decode_dev(le64_to_cpu(dev->huge)); 2268c2ecf20Sopenharmony_ci else { 2278c2ecf20Sopenharmony_ci err = 13; 2288c2ecf20Sopenharmony_ci goto out_invalid; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci memcpy(ui->data, ino->data, ui->data_len); 2318c2ecf20Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 2328c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, rdev); 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci case S_IFSOCK: 2368c2ecf20Sopenharmony_ci case S_IFIFO: 2378c2ecf20Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 2388c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, 0); 2398c2ecf20Sopenharmony_ci if (ui->data_len != 0) { 2408c2ecf20Sopenharmony_ci err = 14; 2418c2ecf20Sopenharmony_ci goto out_invalid; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci default: 2458c2ecf20Sopenharmony_ci err = 15; 2468c2ecf20Sopenharmony_ci goto out_invalid; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci kfree(ino); 2508c2ecf20Sopenharmony_ci ubifs_set_inode_flags(inode); 2518c2ecf20Sopenharmony_ci unlock_new_inode(inode); 2528c2ecf20Sopenharmony_ci return inode; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciout_invalid: 2558c2ecf20Sopenharmony_ci ubifs_err(c, "inode %lu validation failed, error %d", inode->i_ino, err); 2568c2ecf20Sopenharmony_ci ubifs_dump_node(c, ino, UBIFS_MAX_INO_NODE_SZ); 2578c2ecf20Sopenharmony_ci ubifs_dump_inode(c, inode); 2588c2ecf20Sopenharmony_ci err = -EINVAL; 2598c2ecf20Sopenharmony_ciout_ino: 2608c2ecf20Sopenharmony_ci kfree(ino); 2618c2ecf20Sopenharmony_ciout: 2628c2ecf20Sopenharmony_ci ubifs_err(c, "failed to read inode %lu, error %d", inode->i_ino, err); 2638c2ecf20Sopenharmony_ci iget_failed(inode); 2648c2ecf20Sopenharmony_ci return ERR_PTR(err); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic struct inode *ubifs_alloc_inode(struct super_block *sb) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct ubifs_inode *ui; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ui = kmem_cache_alloc(ubifs_inode_slab, GFP_NOFS); 2728c2ecf20Sopenharmony_ci if (!ui) 2738c2ecf20Sopenharmony_ci return NULL; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci memset((void *)ui + sizeof(struct inode), 0, 2768c2ecf20Sopenharmony_ci sizeof(struct ubifs_inode) - sizeof(struct inode)); 2778c2ecf20Sopenharmony_ci mutex_init(&ui->ui_mutex); 2788c2ecf20Sopenharmony_ci init_rwsem(&ui->xattr_sem); 2798c2ecf20Sopenharmony_ci spin_lock_init(&ui->ui_lock); 2808c2ecf20Sopenharmony_ci return &ui->vfs_inode; 2818c2ecf20Sopenharmony_ci}; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void ubifs_free_inode(struct inode *inode) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci kfree(ui->data); 2888c2ecf20Sopenharmony_ci fscrypt_free_inode(inode); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci kmem_cache_free(ubifs_inode_slab, ui); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * Note, Linux write-back code calls this without 'i_mutex'. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_cistatic int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci int err = 0; 2998c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 3008c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ubifs_assert(c, !ui->xattr); 3038c2ecf20Sopenharmony_ci if (is_bad_inode(inode)) 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * Due to races between write-back forced by budgeting 3098c2ecf20Sopenharmony_ci * (see 'sync_some_inodes()') and background write-back, the inode may 3108c2ecf20Sopenharmony_ci * have already been synchronized, do not do this again. This might 3118c2ecf20Sopenharmony_ci * also happen if it was synchronized in an VFS operation, e.g. 3128c2ecf20Sopenharmony_ci * 'ubifs_link()'. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci if (!ui->dirty) { 3158c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* 3208c2ecf20Sopenharmony_ci * As an optimization, do not write orphan inodes to the media just 3218c2ecf20Sopenharmony_ci * because this is not needed. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci dbg_gen("inode %lu, mode %#x, nlink %u", 3248c2ecf20Sopenharmony_ci inode->i_ino, (int)inode->i_mode, inode->i_nlink); 3258c2ecf20Sopenharmony_ci if (inode->i_nlink) { 3268c2ecf20Sopenharmony_ci err = ubifs_jnl_write_inode(c, inode); 3278c2ecf20Sopenharmony_ci if (err) 3288c2ecf20Sopenharmony_ci ubifs_err(c, "can't write inode %lu, error %d", 3298c2ecf20Sopenharmony_ci inode->i_ino, err); 3308c2ecf20Sopenharmony_ci else 3318c2ecf20Sopenharmony_ci err = dbg_check_inode_size(c, inode, ui->ui_size); 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ui->dirty = 0; 3358c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 3368c2ecf20Sopenharmony_ci ubifs_release_dirty_inode_budget(c, ui); 3378c2ecf20Sopenharmony_ci return err; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int ubifs_drop_inode(struct inode *inode) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci int drop = generic_drop_inode(inode); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!drop) 3458c2ecf20Sopenharmony_ci drop = fscrypt_drop_inode(inode); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return drop; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic void ubifs_evict_inode(struct inode *inode) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci int err; 3538c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 3548c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (ui->xattr) 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Extended attribute inode deletions are fully handled in 3598c2ecf20Sopenharmony_ci * 'ubifs_removexattr()'. These inodes are special and have 3608c2ecf20Sopenharmony_ci * limited usage, so there is nothing to do here. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci goto out; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode); 3658c2ecf20Sopenharmony_ci ubifs_assert(c, !atomic_read(&inode->i_count)); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (inode->i_nlink) 3708c2ecf20Sopenharmony_ci goto done; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (is_bad_inode(inode)) 3738c2ecf20Sopenharmony_ci goto out; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ui->ui_size = inode->i_size = 0; 3768c2ecf20Sopenharmony_ci err = ubifs_jnl_delete_inode(c, inode); 3778c2ecf20Sopenharmony_ci if (err) 3788c2ecf20Sopenharmony_ci /* 3798c2ecf20Sopenharmony_ci * Worst case we have a lost orphan inode wasting space, so a 3808c2ecf20Sopenharmony_ci * simple error message is OK here. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci ubifs_err(c, "can't delete inode %lu, error %d", 3838c2ecf20Sopenharmony_ci inode->i_ino, err); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ciout: 3868c2ecf20Sopenharmony_ci if (ui->dirty) 3878c2ecf20Sopenharmony_ci ubifs_release_dirty_inode_budget(c, ui); 3888c2ecf20Sopenharmony_ci else { 3898c2ecf20Sopenharmony_ci /* We've deleted something - clean the "no space" flags */ 3908c2ecf20Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 3918c2ecf20Sopenharmony_ci smp_wmb(); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_cidone: 3948c2ecf20Sopenharmony_ci clear_inode(inode); 3958c2ecf20Sopenharmony_ci fscrypt_put_encryption_info(inode); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void ubifs_dirty_inode(struct inode *inode, int flags) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct ubifs_info *c = inode->i_sb->s_fs_info; 4018c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ubifs_assert(c, mutex_is_locked(&ui->ui_mutex)); 4048c2ecf20Sopenharmony_ci if (!ui->dirty) { 4058c2ecf20Sopenharmony_ci ui->dirty = 1; 4068c2ecf20Sopenharmony_ci dbg_gen("inode %lu", inode->i_ino); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct ubifs_info *c = dentry->d_sb->s_fs_info; 4138c2ecf20Sopenharmony_ci unsigned long long free; 4148c2ecf20Sopenharmony_ci __le32 *uuid = (__le32 *)c->uuid; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci free = ubifs_get_free_space(c); 4178c2ecf20Sopenharmony_ci dbg_gen("free space %lld bytes (%lld blocks)", 4188c2ecf20Sopenharmony_ci free, free >> UBIFS_BLOCK_SHIFT); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci buf->f_type = UBIFS_SUPER_MAGIC; 4218c2ecf20Sopenharmony_ci buf->f_bsize = UBIFS_BLOCK_SIZE; 4228c2ecf20Sopenharmony_ci buf->f_blocks = c->block_cnt; 4238c2ecf20Sopenharmony_ci buf->f_bfree = free >> UBIFS_BLOCK_SHIFT; 4248c2ecf20Sopenharmony_ci if (free > c->report_rp_size) 4258c2ecf20Sopenharmony_ci buf->f_bavail = (free - c->report_rp_size) >> UBIFS_BLOCK_SHIFT; 4268c2ecf20Sopenharmony_ci else 4278c2ecf20Sopenharmony_ci buf->f_bavail = 0; 4288c2ecf20Sopenharmony_ci buf->f_files = 0; 4298c2ecf20Sopenharmony_ci buf->f_ffree = 0; 4308c2ecf20Sopenharmony_ci buf->f_namelen = UBIFS_MAX_NLEN; 4318c2ecf20Sopenharmony_ci buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]); 4328c2ecf20Sopenharmony_ci buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]); 4338c2ecf20Sopenharmony_ci ubifs_assert(c, buf->f_bfree <= c->block_cnt); 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int ubifs_show_options(struct seq_file *s, struct dentry *root) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct ubifs_info *c = root->d_sb->s_fs_info; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (c->mount_opts.unmount_mode == 2) 4428c2ecf20Sopenharmony_ci seq_puts(s, ",fast_unmount"); 4438c2ecf20Sopenharmony_ci else if (c->mount_opts.unmount_mode == 1) 4448c2ecf20Sopenharmony_ci seq_puts(s, ",norm_unmount"); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (c->mount_opts.bulk_read == 2) 4478c2ecf20Sopenharmony_ci seq_puts(s, ",bulk_read"); 4488c2ecf20Sopenharmony_ci else if (c->mount_opts.bulk_read == 1) 4498c2ecf20Sopenharmony_ci seq_puts(s, ",no_bulk_read"); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (c->mount_opts.chk_data_crc == 2) 4528c2ecf20Sopenharmony_ci seq_puts(s, ",chk_data_crc"); 4538c2ecf20Sopenharmony_ci else if (c->mount_opts.chk_data_crc == 1) 4548c2ecf20Sopenharmony_ci seq_puts(s, ",no_chk_data_crc"); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (c->mount_opts.override_compr) { 4578c2ecf20Sopenharmony_ci seq_printf(s, ",compr=%s", 4588c2ecf20Sopenharmony_ci ubifs_compr_name(c, c->mount_opts.compr_type)); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci seq_printf(s, ",assert=%s", ubifs_assert_action_name(c)); 4628c2ecf20Sopenharmony_ci seq_printf(s, ",ubi=%d,vol=%d", c->vi.ubi_num, c->vi.vol_id); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int ubifs_sync_fs(struct super_block *sb, int wait) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int i, err; 4708c2ecf20Sopenharmony_ci struct ubifs_info *c = sb->s_fs_info; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* 4738c2ecf20Sopenharmony_ci * Zero @wait is just an advisory thing to help the file system shove 4748c2ecf20Sopenharmony_ci * lots of data into the queues, and there will be the second 4758c2ecf20Sopenharmony_ci * '->sync_fs()' call, with non-zero @wait. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_ci if (!wait) 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* 4818c2ecf20Sopenharmony_ci * Synchronize write buffers, because 'ubifs_run_commit()' does not 4828c2ecf20Sopenharmony_ci * do this if it waits for an already running commit. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 4858c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync(&c->jheads[i].wbuf); 4868c2ecf20Sopenharmony_ci if (err) 4878c2ecf20Sopenharmony_ci return err; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * Strictly speaking, it is not necessary to commit the journal here, 4928c2ecf20Sopenharmony_ci * synchronizing write-buffers would be enough. But committing makes 4938c2ecf20Sopenharmony_ci * UBIFS free space predictions much more accurate, so we want to let 4948c2ecf20Sopenharmony_ci * the user be able to get more accurate results of 'statfs()' after 4958c2ecf20Sopenharmony_ci * they synchronize the file system. 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_ci err = ubifs_run_commit(c); 4988c2ecf20Sopenharmony_ci if (err) 4998c2ecf20Sopenharmony_ci return err; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return ubi_sync(c->vi.ubi_num); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * init_constants_early - initialize UBIFS constants. 5068c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * This function initialize UBIFS constants which do not need the superblock to 5098c2ecf20Sopenharmony_ci * be read. It also checks that the UBI volume satisfies basic UBIFS 5108c2ecf20Sopenharmony_ci * requirements. Returns zero in case of success and a negative error code in 5118c2ecf20Sopenharmony_ci * case of failure. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_cistatic int init_constants_early(struct ubifs_info *c) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci if (c->vi.corrupted) { 5168c2ecf20Sopenharmony_ci ubifs_warn(c, "UBI volume is corrupted - read-only mode"); 5178c2ecf20Sopenharmony_ci c->ro_media = 1; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (c->di.ro_mode) { 5218c2ecf20Sopenharmony_ci ubifs_msg(c, "read-only UBI device"); 5228c2ecf20Sopenharmony_ci c->ro_media = 1; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci if (c->vi.vol_type == UBI_STATIC_VOLUME) { 5268c2ecf20Sopenharmony_ci ubifs_msg(c, "static UBI volume - read-only mode"); 5278c2ecf20Sopenharmony_ci c->ro_media = 1; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci c->leb_cnt = c->vi.size; 5318c2ecf20Sopenharmony_ci c->leb_size = c->vi.usable_leb_size; 5328c2ecf20Sopenharmony_ci c->leb_start = c->di.leb_start; 5338c2ecf20Sopenharmony_ci c->half_leb_size = c->leb_size / 2; 5348c2ecf20Sopenharmony_ci c->min_io_size = c->di.min_io_size; 5358c2ecf20Sopenharmony_ci c->min_io_shift = fls(c->min_io_size) - 1; 5368c2ecf20Sopenharmony_ci c->max_write_size = c->di.max_write_size; 5378c2ecf20Sopenharmony_ci c->max_write_shift = fls(c->max_write_size) - 1; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (c->leb_size < UBIFS_MIN_LEB_SZ) { 5408c2ecf20Sopenharmony_ci ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes", 5418c2ecf20Sopenharmony_ci c->leb_size, UBIFS_MIN_LEB_SZ); 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (c->leb_cnt < UBIFS_MIN_LEB_CNT) { 5468c2ecf20Sopenharmony_ci ubifs_errc(c, "too few LEBs (%d), min. is %d", 5478c2ecf20Sopenharmony_ci c->leb_cnt, UBIFS_MIN_LEB_CNT); 5488c2ecf20Sopenharmony_ci return -EINVAL; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (!is_power_of_2(c->min_io_size)) { 5528c2ecf20Sopenharmony_ci ubifs_errc(c, "bad min. I/O size %d", c->min_io_size); 5538c2ecf20Sopenharmony_ci return -EINVAL; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * Maximum write size has to be greater or equivalent to min. I/O 5588c2ecf20Sopenharmony_ci * size, and be multiple of min. I/O size. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ci if (c->max_write_size < c->min_io_size || 5618c2ecf20Sopenharmony_ci c->max_write_size % c->min_io_size || 5628c2ecf20Sopenharmony_ci !is_power_of_2(c->max_write_size)) { 5638c2ecf20Sopenharmony_ci ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit", 5648c2ecf20Sopenharmony_ci c->max_write_size, c->min_io_size); 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* 5698c2ecf20Sopenharmony_ci * UBIFS aligns all node to 8-byte boundary, so to make function in 5708c2ecf20Sopenharmony_ci * io.c simpler, assume minimum I/O unit size to be 8 bytes if it is 5718c2ecf20Sopenharmony_ci * less than 8. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_ci if (c->min_io_size < 8) { 5748c2ecf20Sopenharmony_ci c->min_io_size = 8; 5758c2ecf20Sopenharmony_ci c->min_io_shift = 3; 5768c2ecf20Sopenharmony_ci if (c->max_write_size < c->min_io_size) { 5778c2ecf20Sopenharmony_ci c->max_write_size = c->min_io_size; 5788c2ecf20Sopenharmony_ci c->max_write_shift = c->min_io_shift; 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci c->ref_node_alsz = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); 5838c2ecf20Sopenharmony_ci c->mst_node_alsz = ALIGN(UBIFS_MST_NODE_SZ, c->min_io_size); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * Initialize node length ranges which are mostly needed for node 5878c2ecf20Sopenharmony_ci * length validation. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci c->ranges[UBIFS_PAD_NODE].len = UBIFS_PAD_NODE_SZ; 5908c2ecf20Sopenharmony_ci c->ranges[UBIFS_SB_NODE].len = UBIFS_SB_NODE_SZ; 5918c2ecf20Sopenharmony_ci c->ranges[UBIFS_MST_NODE].len = UBIFS_MST_NODE_SZ; 5928c2ecf20Sopenharmony_ci c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ; 5938c2ecf20Sopenharmony_ci c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ; 5948c2ecf20Sopenharmony_ci c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ; 5958c2ecf20Sopenharmony_ci c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ; 5968c2ecf20Sopenharmony_ci c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ + 5978c2ecf20Sopenharmony_ci UBIFS_MAX_HMAC_LEN; 5988c2ecf20Sopenharmony_ci c->ranges[UBIFS_SIG_NODE].min_len = UBIFS_SIG_NODE_SZ; 5998c2ecf20Sopenharmony_ci c->ranges[UBIFS_SIG_NODE].max_len = c->leb_size - UBIFS_SB_NODE_SZ; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ; 6028c2ecf20Sopenharmony_ci c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ; 6038c2ecf20Sopenharmony_ci c->ranges[UBIFS_ORPH_NODE].min_len = 6048c2ecf20Sopenharmony_ci UBIFS_ORPH_NODE_SZ + sizeof(__le64); 6058c2ecf20Sopenharmony_ci c->ranges[UBIFS_ORPH_NODE].max_len = c->leb_size; 6068c2ecf20Sopenharmony_ci c->ranges[UBIFS_DENT_NODE].min_len = UBIFS_DENT_NODE_SZ; 6078c2ecf20Sopenharmony_ci c->ranges[UBIFS_DENT_NODE].max_len = UBIFS_MAX_DENT_NODE_SZ; 6088c2ecf20Sopenharmony_ci c->ranges[UBIFS_XENT_NODE].min_len = UBIFS_XENT_NODE_SZ; 6098c2ecf20Sopenharmony_ci c->ranges[UBIFS_XENT_NODE].max_len = UBIFS_MAX_XENT_NODE_SZ; 6108c2ecf20Sopenharmony_ci c->ranges[UBIFS_DATA_NODE].min_len = UBIFS_DATA_NODE_SZ; 6118c2ecf20Sopenharmony_ci c->ranges[UBIFS_DATA_NODE].max_len = UBIFS_MAX_DATA_NODE_SZ; 6128c2ecf20Sopenharmony_ci /* 6138c2ecf20Sopenharmony_ci * Minimum indexing node size is amended later when superblock is 6148c2ecf20Sopenharmony_ci * read and the key length is known. 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci c->ranges[UBIFS_IDX_NODE].min_len = UBIFS_IDX_NODE_SZ + UBIFS_BRANCH_SZ; 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * Maximum indexing node size is amended later when superblock is 6198c2ecf20Sopenharmony_ci * read and the fanout is known. 6208c2ecf20Sopenharmony_ci */ 6218c2ecf20Sopenharmony_ci c->ranges[UBIFS_IDX_NODE].max_len = INT_MAX; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* 6248c2ecf20Sopenharmony_ci * Initialize dead and dark LEB space watermarks. See gc.c for comments 6258c2ecf20Sopenharmony_ci * about these values. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); 6288c2ecf20Sopenharmony_ci c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * Calculate how many bytes would be wasted at the end of LEB if it was 6328c2ecf20Sopenharmony_ci * fully filled with data nodes of maximum size. This is used in 6338c2ecf20Sopenharmony_ci * calculations when reporting free space. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_ci c->leb_overhead = c->leb_size % UBIFS_MAX_DATA_NODE_SZ; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* Buffer size for bulk-reads */ 6388c2ecf20Sopenharmony_ci c->max_bu_buf_len = UBIFS_MAX_BULK_READ * UBIFS_MAX_DATA_NODE_SZ; 6398c2ecf20Sopenharmony_ci if (c->max_bu_buf_len > c->leb_size) 6408c2ecf20Sopenharmony_ci c->max_bu_buf_len = c->leb_size; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* Log is ready, preserve one LEB for commits. */ 6438c2ecf20Sopenharmony_ci c->min_log_bytes = c->leb_size; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci/** 6498c2ecf20Sopenharmony_ci * bud_wbuf_callback - bud LEB write-buffer synchronization call-back. 6508c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6518c2ecf20Sopenharmony_ci * @lnum: LEB the write-buffer was synchronized to 6528c2ecf20Sopenharmony_ci * @free: how many free bytes left in this LEB 6538c2ecf20Sopenharmony_ci * @pad: how many bytes were padded 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * This is a callback function which is called by the I/O unit when the 6568c2ecf20Sopenharmony_ci * write-buffer is synchronized. We need this to correctly maintain space 6578c2ecf20Sopenharmony_ci * accounting in bud logical eraseblocks. This function returns zero in case of 6588c2ecf20Sopenharmony_ci * success and a negative error code in case of failure. 6598c2ecf20Sopenharmony_ci * 6608c2ecf20Sopenharmony_ci * This function actually belongs to the journal, but we keep it here because 6618c2ecf20Sopenharmony_ci * we want to keep it static. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_cistatic int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci return ubifs_update_one_lp(c, lnum, free, pad, 0, 0); 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci/* 6698c2ecf20Sopenharmony_ci * init_constants_sb - initialize UBIFS constants. 6708c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6718c2ecf20Sopenharmony_ci * 6728c2ecf20Sopenharmony_ci * This is a helper function which initializes various UBIFS constants after 6738c2ecf20Sopenharmony_ci * the superblock has been read. It also checks various UBIFS parameters and 6748c2ecf20Sopenharmony_ci * makes sure they are all right. Returns zero in case of success and a 6758c2ecf20Sopenharmony_ci * negative error code in case of failure. 6768c2ecf20Sopenharmony_ci */ 6778c2ecf20Sopenharmony_cistatic int init_constants_sb(struct ubifs_info *c) 6788c2ecf20Sopenharmony_ci{ 6798c2ecf20Sopenharmony_ci int tmp, err; 6808c2ecf20Sopenharmony_ci long long tmp64; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci c->main_bytes = (long long)c->main_lebs * c->leb_size; 6838c2ecf20Sopenharmony_ci c->max_znode_sz = sizeof(struct ubifs_znode) + 6848c2ecf20Sopenharmony_ci c->fanout * sizeof(struct ubifs_zbranch); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci tmp = ubifs_idx_node_sz(c, 1); 6878c2ecf20Sopenharmony_ci c->ranges[UBIFS_IDX_NODE].min_len = tmp; 6888c2ecf20Sopenharmony_ci c->min_idx_node_sz = ALIGN(tmp, 8); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci tmp = ubifs_idx_node_sz(c, c->fanout); 6918c2ecf20Sopenharmony_ci c->ranges[UBIFS_IDX_NODE].max_len = tmp; 6928c2ecf20Sopenharmony_ci c->max_idx_node_sz = ALIGN(tmp, 8); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* Make sure LEB size is large enough to fit full commit */ 6958c2ecf20Sopenharmony_ci tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt; 6968c2ecf20Sopenharmony_ci tmp = ALIGN(tmp, c->min_io_size); 6978c2ecf20Sopenharmony_ci if (tmp > c->leb_size) { 6988c2ecf20Sopenharmony_ci ubifs_err(c, "too small LEB size %d, at least %d needed", 6998c2ecf20Sopenharmony_ci c->leb_size, tmp); 7008c2ecf20Sopenharmony_ci return -EINVAL; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci /* 7048c2ecf20Sopenharmony_ci * Make sure that the log is large enough to fit reference nodes for 7058c2ecf20Sopenharmony_ci * all buds plus one reserved LEB. 7068c2ecf20Sopenharmony_ci */ 7078c2ecf20Sopenharmony_ci tmp64 = c->max_bud_bytes + c->leb_size - 1; 7088c2ecf20Sopenharmony_ci c->max_bud_cnt = div_u64(tmp64, c->leb_size); 7098c2ecf20Sopenharmony_ci tmp = (c->ref_node_alsz * c->max_bud_cnt + c->leb_size - 1); 7108c2ecf20Sopenharmony_ci tmp /= c->leb_size; 7118c2ecf20Sopenharmony_ci tmp += 1; 7128c2ecf20Sopenharmony_ci if (c->log_lebs < tmp) { 7138c2ecf20Sopenharmony_ci ubifs_err(c, "too small log %d LEBs, required min. %d LEBs", 7148c2ecf20Sopenharmony_ci c->log_lebs, tmp); 7158c2ecf20Sopenharmony_ci return -EINVAL; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * When budgeting we assume worst-case scenarios when the pages are not 7208c2ecf20Sopenharmony_ci * be compressed and direntries are of the maximum size. 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * Note, data, which may be stored in inodes is budgeted separately, so 7238c2ecf20Sopenharmony_ci * it is not included into 'c->bi.inode_budget'. 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_ci c->bi.page_budget = UBIFS_MAX_DATA_NODE_SZ * UBIFS_BLOCKS_PER_PAGE; 7268c2ecf20Sopenharmony_ci c->bi.inode_budget = UBIFS_INO_NODE_SZ; 7278c2ecf20Sopenharmony_ci c->bi.dent_budget = UBIFS_MAX_DENT_NODE_SZ; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* 7308c2ecf20Sopenharmony_ci * When the amount of flash space used by buds becomes 7318c2ecf20Sopenharmony_ci * 'c->max_bud_bytes', UBIFS just blocks all writers and starts commit. 7328c2ecf20Sopenharmony_ci * The writers are unblocked when the commit is finished. To avoid 7338c2ecf20Sopenharmony_ci * writers to be blocked UBIFS initiates background commit in advance, 7348c2ecf20Sopenharmony_ci * when number of bud bytes becomes above the limit defined below. 7358c2ecf20Sopenharmony_ci */ 7368c2ecf20Sopenharmony_ci c->bg_bud_bytes = (c->max_bud_bytes * 13) >> 4; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* 7398c2ecf20Sopenharmony_ci * Ensure minimum journal size. All the bytes in the journal heads are 7408c2ecf20Sopenharmony_ci * considered to be used, when calculating the current journal usage. 7418c2ecf20Sopenharmony_ci * Consequently, if the journal is too small, UBIFS will treat it as 7428c2ecf20Sopenharmony_ci * always full. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci tmp64 = (long long)(c->jhead_cnt + 1) * c->leb_size + 1; 7458c2ecf20Sopenharmony_ci if (c->bg_bud_bytes < tmp64) 7468c2ecf20Sopenharmony_ci c->bg_bud_bytes = tmp64; 7478c2ecf20Sopenharmony_ci if (c->max_bud_bytes < tmp64 + c->leb_size) 7488c2ecf20Sopenharmony_ci c->max_bud_bytes = tmp64 + c->leb_size; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci err = ubifs_calc_lpt_geom(c); 7518c2ecf20Sopenharmony_ci if (err) 7528c2ecf20Sopenharmony_ci return err; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci /* Initialize effective LEB size used in budgeting calculations */ 7558c2ecf20Sopenharmony_ci c->idx_leb_size = c->leb_size - c->max_idx_node_sz; 7568c2ecf20Sopenharmony_ci return 0; 7578c2ecf20Sopenharmony_ci} 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci/* 7608c2ecf20Sopenharmony_ci * init_constants_master - initialize UBIFS constants. 7618c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * This is a helper function which initializes various UBIFS constants after 7648c2ecf20Sopenharmony_ci * the master node has been read. It also checks various UBIFS parameters and 7658c2ecf20Sopenharmony_ci * makes sure they are all right. 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_cistatic void init_constants_master(struct ubifs_info *c) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci long long tmp64; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c); 7728c2ecf20Sopenharmony_ci c->report_rp_size = ubifs_reported_space(c, c->rp_size); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci /* 7758c2ecf20Sopenharmony_ci * Calculate total amount of FS blocks. This number is not used 7768c2ecf20Sopenharmony_ci * internally because it does not make much sense for UBIFS, but it is 7778c2ecf20Sopenharmony_ci * necessary to report something for the 'statfs()' call. 7788c2ecf20Sopenharmony_ci * 7798c2ecf20Sopenharmony_ci * Subtract the LEB reserved for GC, the LEB which is reserved for 7808c2ecf20Sopenharmony_ci * deletions, minimum LEBs for the index, and assume only one journal 7818c2ecf20Sopenharmony_ci * head is available. 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_ci tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1; 7848c2ecf20Sopenharmony_ci tmp64 *= (long long)c->leb_size - c->leb_overhead; 7858c2ecf20Sopenharmony_ci tmp64 = ubifs_reported_space(c, tmp64); 7868c2ecf20Sopenharmony_ci c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/** 7908c2ecf20Sopenharmony_ci * take_gc_lnum - reserve GC LEB. 7918c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 7928c2ecf20Sopenharmony_ci * 7938c2ecf20Sopenharmony_ci * This function ensures that the LEB reserved for garbage collection is marked 7948c2ecf20Sopenharmony_ci * as "taken" in lprops. We also have to set free space to LEB size and dirty 7958c2ecf20Sopenharmony_ci * space to zero, because lprops may contain out-of-date information if the 7968c2ecf20Sopenharmony_ci * file-system was un-mounted before it has been committed. This function 7978c2ecf20Sopenharmony_ci * returns zero in case of success and a negative error code in case of 7988c2ecf20Sopenharmony_ci * failure. 7998c2ecf20Sopenharmony_ci */ 8008c2ecf20Sopenharmony_cistatic int take_gc_lnum(struct ubifs_info *c) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci int err; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (c->gc_lnum == -1) { 8058c2ecf20Sopenharmony_ci ubifs_err(c, "no LEB for GC"); 8068c2ecf20Sopenharmony_ci return -EINVAL; 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci /* And we have to tell lprops that this LEB is taken */ 8108c2ecf20Sopenharmony_ci err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0, 8118c2ecf20Sopenharmony_ci LPROPS_TAKEN, 0, 0); 8128c2ecf20Sopenharmony_ci return err; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci/** 8168c2ecf20Sopenharmony_ci * alloc_wbufs - allocate write-buffers. 8178c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8188c2ecf20Sopenharmony_ci * 8198c2ecf20Sopenharmony_ci * This helper function allocates and initializes UBIFS write-buffers. Returns 8208c2ecf20Sopenharmony_ci * zero in case of success and %-ENOMEM in case of failure. 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_cistatic int alloc_wbufs(struct ubifs_info *c) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci int i, err; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci c->jheads = kcalloc(c->jhead_cnt, sizeof(struct ubifs_jhead), 8278c2ecf20Sopenharmony_ci GFP_KERNEL); 8288c2ecf20Sopenharmony_ci if (!c->jheads) 8298c2ecf20Sopenharmony_ci return -ENOMEM; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Initialize journal heads */ 8328c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 8338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->jheads[i].buds_list); 8348c2ecf20Sopenharmony_ci err = ubifs_wbuf_init(c, &c->jheads[i].wbuf); 8358c2ecf20Sopenharmony_ci if (err) 8368c2ecf20Sopenharmony_ci goto out_wbuf; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; 8398c2ecf20Sopenharmony_ci c->jheads[i].wbuf.jhead = i; 8408c2ecf20Sopenharmony_ci c->jheads[i].grouped = 1; 8418c2ecf20Sopenharmony_ci c->jheads[i].log_hash = ubifs_hash_get_desc(c); 8428c2ecf20Sopenharmony_ci if (IS_ERR(c->jheads[i].log_hash)) { 8438c2ecf20Sopenharmony_ci err = PTR_ERR(c->jheads[i].log_hash); 8448c2ecf20Sopenharmony_ci goto out_log_hash; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci /* 8498c2ecf20Sopenharmony_ci * Garbage Collector head does not need to be synchronized by timer. 8508c2ecf20Sopenharmony_ci * Also GC head nodes are not grouped. 8518c2ecf20Sopenharmony_ci */ 8528c2ecf20Sopenharmony_ci c->jheads[GCHD].wbuf.no_timer = 1; 8538c2ecf20Sopenharmony_ci c->jheads[GCHD].grouped = 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci return 0; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ciout_log_hash: 8588c2ecf20Sopenharmony_ci kfree(c->jheads[i].wbuf.buf); 8598c2ecf20Sopenharmony_ci kfree(c->jheads[i].wbuf.inodes); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ciout_wbuf: 8628c2ecf20Sopenharmony_ci while (i--) { 8638c2ecf20Sopenharmony_ci kfree(c->jheads[i].wbuf.buf); 8648c2ecf20Sopenharmony_ci kfree(c->jheads[i].wbuf.inodes); 8658c2ecf20Sopenharmony_ci kfree(c->jheads[i].log_hash); 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci kfree(c->jheads); 8688c2ecf20Sopenharmony_ci c->jheads = NULL; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return err; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci/** 8748c2ecf20Sopenharmony_ci * free_wbufs - free write-buffers. 8758c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_cistatic void free_wbufs(struct ubifs_info *c) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci int i; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (c->jheads) { 8828c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 8838c2ecf20Sopenharmony_ci kfree(c->jheads[i].wbuf.buf); 8848c2ecf20Sopenharmony_ci kfree(c->jheads[i].wbuf.inodes); 8858c2ecf20Sopenharmony_ci kfree(c->jheads[i].log_hash); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci kfree(c->jheads); 8888c2ecf20Sopenharmony_ci c->jheads = NULL; 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci/** 8938c2ecf20Sopenharmony_ci * free_orphans - free orphans. 8948c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_cistatic void free_orphans(struct ubifs_info *c) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct ubifs_orphan *orph; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci while (c->orph_dnext) { 9018c2ecf20Sopenharmony_ci orph = c->orph_dnext; 9028c2ecf20Sopenharmony_ci c->orph_dnext = orph->dnext; 9038c2ecf20Sopenharmony_ci list_del(&orph->list); 9048c2ecf20Sopenharmony_ci kfree(orph); 9058c2ecf20Sopenharmony_ci } 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci while (!list_empty(&c->orph_list)) { 9088c2ecf20Sopenharmony_ci orph = list_entry(c->orph_list.next, struct ubifs_orphan, list); 9098c2ecf20Sopenharmony_ci list_del(&orph->list); 9108c2ecf20Sopenharmony_ci kfree(orph); 9118c2ecf20Sopenharmony_ci ubifs_err(c, "orphan list not empty at unmount"); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci vfree(c->orph_buf); 9158c2ecf20Sopenharmony_ci c->orph_buf = NULL; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci/** 9198c2ecf20Sopenharmony_ci * free_buds - free per-bud objects. 9208c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_cistatic void free_buds(struct ubifs_info *c) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci struct ubifs_bud *bud, *n; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(bud, n, &c->buds, rb) 9278c2ecf20Sopenharmony_ci kfree(bud); 9288c2ecf20Sopenharmony_ci} 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci/** 9318c2ecf20Sopenharmony_ci * check_volume_empty - check if the UBI volume is empty. 9328c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9338c2ecf20Sopenharmony_ci * 9348c2ecf20Sopenharmony_ci * This function checks if the UBIFS volume is empty by looking if its LEBs are 9358c2ecf20Sopenharmony_ci * mapped or not. The result of checking is stored in the @c->empty variable. 9368c2ecf20Sopenharmony_ci * Returns zero in case of success and a negative error code in case of 9378c2ecf20Sopenharmony_ci * failure. 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_cistatic int check_volume_empty(struct ubifs_info *c) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci int lnum, err; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci c->empty = 1; 9448c2ecf20Sopenharmony_ci for (lnum = 0; lnum < c->leb_cnt; lnum++) { 9458c2ecf20Sopenharmony_ci err = ubifs_is_mapped(c, lnum); 9468c2ecf20Sopenharmony_ci if (unlikely(err < 0)) 9478c2ecf20Sopenharmony_ci return err; 9488c2ecf20Sopenharmony_ci if (err == 1) { 9498c2ecf20Sopenharmony_ci c->empty = 0; 9508c2ecf20Sopenharmony_ci break; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci cond_resched(); 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/* 9608c2ecf20Sopenharmony_ci * UBIFS mount options. 9618c2ecf20Sopenharmony_ci * 9628c2ecf20Sopenharmony_ci * Opt_fast_unmount: do not run a journal commit before un-mounting 9638c2ecf20Sopenharmony_ci * Opt_norm_unmount: run a journal commit before un-mounting 9648c2ecf20Sopenharmony_ci * Opt_bulk_read: enable bulk-reads 9658c2ecf20Sopenharmony_ci * Opt_no_bulk_read: disable bulk-reads 9668c2ecf20Sopenharmony_ci * Opt_chk_data_crc: check CRCs when reading data nodes 9678c2ecf20Sopenharmony_ci * Opt_no_chk_data_crc: do not check CRCs when reading data nodes 9688c2ecf20Sopenharmony_ci * Opt_override_compr: override default compressor 9698c2ecf20Sopenharmony_ci * Opt_assert: set ubifs_assert() action 9708c2ecf20Sopenharmony_ci * Opt_auth_key: The key name used for authentication 9718c2ecf20Sopenharmony_ci * Opt_auth_hash_name: The hash type used for authentication 9728c2ecf20Sopenharmony_ci * Opt_err: just end of array marker 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_cienum { 9758c2ecf20Sopenharmony_ci Opt_fast_unmount, 9768c2ecf20Sopenharmony_ci Opt_norm_unmount, 9778c2ecf20Sopenharmony_ci Opt_bulk_read, 9788c2ecf20Sopenharmony_ci Opt_no_bulk_read, 9798c2ecf20Sopenharmony_ci Opt_chk_data_crc, 9808c2ecf20Sopenharmony_ci Opt_no_chk_data_crc, 9818c2ecf20Sopenharmony_ci Opt_override_compr, 9828c2ecf20Sopenharmony_ci Opt_assert, 9838c2ecf20Sopenharmony_ci Opt_auth_key, 9848c2ecf20Sopenharmony_ci Opt_auth_hash_name, 9858c2ecf20Sopenharmony_ci Opt_ignore, 9868c2ecf20Sopenharmony_ci Opt_err, 9878c2ecf20Sopenharmony_ci}; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic const match_table_t tokens = { 9908c2ecf20Sopenharmony_ci {Opt_fast_unmount, "fast_unmount"}, 9918c2ecf20Sopenharmony_ci {Opt_norm_unmount, "norm_unmount"}, 9928c2ecf20Sopenharmony_ci {Opt_bulk_read, "bulk_read"}, 9938c2ecf20Sopenharmony_ci {Opt_no_bulk_read, "no_bulk_read"}, 9948c2ecf20Sopenharmony_ci {Opt_chk_data_crc, "chk_data_crc"}, 9958c2ecf20Sopenharmony_ci {Opt_no_chk_data_crc, "no_chk_data_crc"}, 9968c2ecf20Sopenharmony_ci {Opt_override_compr, "compr=%s"}, 9978c2ecf20Sopenharmony_ci {Opt_auth_key, "auth_key=%s"}, 9988c2ecf20Sopenharmony_ci {Opt_auth_hash_name, "auth_hash_name=%s"}, 9998c2ecf20Sopenharmony_ci {Opt_ignore, "ubi=%s"}, 10008c2ecf20Sopenharmony_ci {Opt_ignore, "vol=%s"}, 10018c2ecf20Sopenharmony_ci {Opt_assert, "assert=%s"}, 10028c2ecf20Sopenharmony_ci {Opt_err, NULL}, 10038c2ecf20Sopenharmony_ci}; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/** 10068c2ecf20Sopenharmony_ci * parse_standard_option - parse a standard mount option. 10078c2ecf20Sopenharmony_ci * @option: the option to parse 10088c2ecf20Sopenharmony_ci * 10098c2ecf20Sopenharmony_ci * Normally, standard mount options like "sync" are passed to file-systems as 10108c2ecf20Sopenharmony_ci * flags. However, when a "rootflags=" kernel boot parameter is used, they may 10118c2ecf20Sopenharmony_ci * be present in the options string. This function tries to deal with this 10128c2ecf20Sopenharmony_ci * situation and parse standard options. Returns 0 if the option was not 10138c2ecf20Sopenharmony_ci * recognized, and the corresponding integer flag if it was. 10148c2ecf20Sopenharmony_ci * 10158c2ecf20Sopenharmony_ci * UBIFS is only interested in the "sync" option, so do not check for anything 10168c2ecf20Sopenharmony_ci * else. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_cistatic int parse_standard_option(const char *option) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci pr_notice("UBIFS: parse %s\n", option); 10228c2ecf20Sopenharmony_ci if (!strcmp(option, "sync")) 10238c2ecf20Sopenharmony_ci return SB_SYNCHRONOUS; 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci/** 10288c2ecf20Sopenharmony_ci * ubifs_parse_options - parse mount parameters. 10298c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 10308c2ecf20Sopenharmony_ci * @options: parameters to parse 10318c2ecf20Sopenharmony_ci * @is_remount: non-zero if this is FS re-mount 10328c2ecf20Sopenharmony_ci * 10338c2ecf20Sopenharmony_ci * This function parses UBIFS mount options and returns zero in case success 10348c2ecf20Sopenharmony_ci * and a negative error code in case of failure. 10358c2ecf20Sopenharmony_ci */ 10368c2ecf20Sopenharmony_cistatic int ubifs_parse_options(struct ubifs_info *c, char *options, 10378c2ecf20Sopenharmony_ci int is_remount) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci char *p; 10408c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (!options) 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci while ((p = strsep(&options, ","))) { 10468c2ecf20Sopenharmony_ci int token; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (!*p) 10498c2ecf20Sopenharmony_ci continue; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 10528c2ecf20Sopenharmony_ci switch (token) { 10538c2ecf20Sopenharmony_ci /* 10548c2ecf20Sopenharmony_ci * %Opt_fast_unmount and %Opt_norm_unmount options are ignored. 10558c2ecf20Sopenharmony_ci * We accept them in order to be backward-compatible. But this 10568c2ecf20Sopenharmony_ci * should be removed at some point. 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_ci case Opt_fast_unmount: 10598c2ecf20Sopenharmony_ci c->mount_opts.unmount_mode = 2; 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci case Opt_norm_unmount: 10628c2ecf20Sopenharmony_ci c->mount_opts.unmount_mode = 1; 10638c2ecf20Sopenharmony_ci break; 10648c2ecf20Sopenharmony_ci case Opt_bulk_read: 10658c2ecf20Sopenharmony_ci c->mount_opts.bulk_read = 2; 10668c2ecf20Sopenharmony_ci c->bulk_read = 1; 10678c2ecf20Sopenharmony_ci break; 10688c2ecf20Sopenharmony_ci case Opt_no_bulk_read: 10698c2ecf20Sopenharmony_ci c->mount_opts.bulk_read = 1; 10708c2ecf20Sopenharmony_ci c->bulk_read = 0; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci case Opt_chk_data_crc: 10738c2ecf20Sopenharmony_ci c->mount_opts.chk_data_crc = 2; 10748c2ecf20Sopenharmony_ci c->no_chk_data_crc = 0; 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case Opt_no_chk_data_crc: 10778c2ecf20Sopenharmony_ci c->mount_opts.chk_data_crc = 1; 10788c2ecf20Sopenharmony_ci c->no_chk_data_crc = 1; 10798c2ecf20Sopenharmony_ci break; 10808c2ecf20Sopenharmony_ci case Opt_override_compr: 10818c2ecf20Sopenharmony_ci { 10828c2ecf20Sopenharmony_ci char *name = match_strdup(&args[0]); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (!name) 10858c2ecf20Sopenharmony_ci return -ENOMEM; 10868c2ecf20Sopenharmony_ci if (!strcmp(name, "none")) 10878c2ecf20Sopenharmony_ci c->mount_opts.compr_type = UBIFS_COMPR_NONE; 10888c2ecf20Sopenharmony_ci else if (!strcmp(name, "lzo")) 10898c2ecf20Sopenharmony_ci c->mount_opts.compr_type = UBIFS_COMPR_LZO; 10908c2ecf20Sopenharmony_ci else if (!strcmp(name, "zlib")) 10918c2ecf20Sopenharmony_ci c->mount_opts.compr_type = UBIFS_COMPR_ZLIB; 10928c2ecf20Sopenharmony_ci else if (!strcmp(name, "zstd")) 10938c2ecf20Sopenharmony_ci c->mount_opts.compr_type = UBIFS_COMPR_ZSTD; 10948c2ecf20Sopenharmony_ci else { 10958c2ecf20Sopenharmony_ci ubifs_err(c, "unknown compressor \"%s\"", name); //FIXME: is c ready? 10968c2ecf20Sopenharmony_ci kfree(name); 10978c2ecf20Sopenharmony_ci return -EINVAL; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci kfree(name); 11008c2ecf20Sopenharmony_ci c->mount_opts.override_compr = 1; 11018c2ecf20Sopenharmony_ci c->default_compr = c->mount_opts.compr_type; 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci case Opt_assert: 11058c2ecf20Sopenharmony_ci { 11068c2ecf20Sopenharmony_ci char *act = match_strdup(&args[0]); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (!act) 11098c2ecf20Sopenharmony_ci return -ENOMEM; 11108c2ecf20Sopenharmony_ci if (!strcmp(act, "report")) 11118c2ecf20Sopenharmony_ci c->assert_action = ASSACT_REPORT; 11128c2ecf20Sopenharmony_ci else if (!strcmp(act, "read-only")) 11138c2ecf20Sopenharmony_ci c->assert_action = ASSACT_RO; 11148c2ecf20Sopenharmony_ci else if (!strcmp(act, "panic")) 11158c2ecf20Sopenharmony_ci c->assert_action = ASSACT_PANIC; 11168c2ecf20Sopenharmony_ci else { 11178c2ecf20Sopenharmony_ci ubifs_err(c, "unknown assert action \"%s\"", act); 11188c2ecf20Sopenharmony_ci kfree(act); 11198c2ecf20Sopenharmony_ci return -EINVAL; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci kfree(act); 11228c2ecf20Sopenharmony_ci break; 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci case Opt_auth_key: 11258c2ecf20Sopenharmony_ci if (!is_remount) { 11268c2ecf20Sopenharmony_ci c->auth_key_name = kstrdup(args[0].from, 11278c2ecf20Sopenharmony_ci GFP_KERNEL); 11288c2ecf20Sopenharmony_ci if (!c->auth_key_name) 11298c2ecf20Sopenharmony_ci return -ENOMEM; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci case Opt_auth_hash_name: 11338c2ecf20Sopenharmony_ci if (!is_remount) { 11348c2ecf20Sopenharmony_ci c->auth_hash_name = kstrdup(args[0].from, 11358c2ecf20Sopenharmony_ci GFP_KERNEL); 11368c2ecf20Sopenharmony_ci if (!c->auth_hash_name) 11378c2ecf20Sopenharmony_ci return -ENOMEM; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci break; 11408c2ecf20Sopenharmony_ci case Opt_ignore: 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci default: 11438c2ecf20Sopenharmony_ci { 11448c2ecf20Sopenharmony_ci unsigned long flag; 11458c2ecf20Sopenharmony_ci struct super_block *sb = c->vfs_sb; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci flag = parse_standard_option(p); 11488c2ecf20Sopenharmony_ci if (!flag) { 11498c2ecf20Sopenharmony_ci ubifs_err(c, "unrecognized mount option \"%s\" or missing value", 11508c2ecf20Sopenharmony_ci p); 11518c2ecf20Sopenharmony_ci return -EINVAL; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci sb->s_flags |= flag; 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci return 0; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci/* 11638c2ecf20Sopenharmony_ci * ubifs_release_options - release mount parameters which have been dumped. 11648c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_cistatic void ubifs_release_options(struct ubifs_info *c) 11678c2ecf20Sopenharmony_ci{ 11688c2ecf20Sopenharmony_ci kfree(c->auth_key_name); 11698c2ecf20Sopenharmony_ci c->auth_key_name = NULL; 11708c2ecf20Sopenharmony_ci kfree(c->auth_hash_name); 11718c2ecf20Sopenharmony_ci c->auth_hash_name = NULL; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci/** 11758c2ecf20Sopenharmony_ci * destroy_journal - destroy journal data structures. 11768c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 11778c2ecf20Sopenharmony_ci * 11788c2ecf20Sopenharmony_ci * This function destroys journal data structures including those that may have 11798c2ecf20Sopenharmony_ci * been created by recovery functions. 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_cistatic void destroy_journal(struct ubifs_info *c) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci while (!list_empty(&c->unclean_leb_list)) { 11848c2ecf20Sopenharmony_ci struct ubifs_unclean_leb *ucleb; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci ucleb = list_entry(c->unclean_leb_list.next, 11878c2ecf20Sopenharmony_ci struct ubifs_unclean_leb, list); 11888c2ecf20Sopenharmony_ci list_del(&ucleb->list); 11898c2ecf20Sopenharmony_ci kfree(ucleb); 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci while (!list_empty(&c->old_buds)) { 11928c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci bud = list_entry(c->old_buds.next, struct ubifs_bud, list); 11958c2ecf20Sopenharmony_ci list_del(&bud->list); 11968c2ecf20Sopenharmony_ci kfree(bud); 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci ubifs_destroy_idx_gc(c); 11998c2ecf20Sopenharmony_ci ubifs_destroy_size_tree(c); 12008c2ecf20Sopenharmony_ci ubifs_tnc_close(c); 12018c2ecf20Sopenharmony_ci free_buds(c); 12028c2ecf20Sopenharmony_ci} 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci/** 12058c2ecf20Sopenharmony_ci * bu_init - initialize bulk-read information. 12068c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_cistatic void bu_init(struct ubifs_info *c) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci ubifs_assert(c, c->bulk_read == 1); 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci if (c->bu.buf) 12138c2ecf20Sopenharmony_ci return; /* Already initialized */ 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ciagain: 12168c2ecf20Sopenharmony_ci c->bu.buf = kmalloc(c->max_bu_buf_len, GFP_KERNEL | __GFP_NOWARN); 12178c2ecf20Sopenharmony_ci if (!c->bu.buf) { 12188c2ecf20Sopenharmony_ci if (c->max_bu_buf_len > UBIFS_KMALLOC_OK) { 12198c2ecf20Sopenharmony_ci c->max_bu_buf_len = UBIFS_KMALLOC_OK; 12208c2ecf20Sopenharmony_ci goto again; 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci /* Just disable bulk-read */ 12248c2ecf20Sopenharmony_ci ubifs_warn(c, "cannot allocate %d bytes of memory for bulk-read, disabling it", 12258c2ecf20Sopenharmony_ci c->max_bu_buf_len); 12268c2ecf20Sopenharmony_ci c->mount_opts.bulk_read = 1; 12278c2ecf20Sopenharmony_ci c->bulk_read = 0; 12288c2ecf20Sopenharmony_ci return; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci/** 12338c2ecf20Sopenharmony_ci * check_free_space - check if there is enough free space to mount. 12348c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 12358c2ecf20Sopenharmony_ci * 12368c2ecf20Sopenharmony_ci * This function makes sure UBIFS has enough free space to be mounted in 12378c2ecf20Sopenharmony_ci * read/write mode. UBIFS must always have some free space to allow deletions. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_cistatic int check_free_space(struct ubifs_info *c) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci ubifs_assert(c, c->dark_wm > 0); 12428c2ecf20Sopenharmony_ci if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) { 12438c2ecf20Sopenharmony_ci ubifs_err(c, "insufficient free space to mount in R/W mode"); 12448c2ecf20Sopenharmony_ci ubifs_dump_budg(c, &c->bi); 12458c2ecf20Sopenharmony_ci ubifs_dump_lprops(c); 12468c2ecf20Sopenharmony_ci return -ENOSPC; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci return 0; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci/** 12528c2ecf20Sopenharmony_ci * mount_ubifs - mount UBIFS file-system. 12538c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 12548c2ecf20Sopenharmony_ci * 12558c2ecf20Sopenharmony_ci * This function mounts UBIFS file system. Returns zero in case of success and 12568c2ecf20Sopenharmony_ci * a negative error code in case of failure. 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_cistatic int mount_ubifs(struct ubifs_info *c) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci int err; 12618c2ecf20Sopenharmony_ci long long x, y; 12628c2ecf20Sopenharmony_ci size_t sz; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci c->ro_mount = !!sb_rdonly(c->vfs_sb); 12658c2ecf20Sopenharmony_ci /* Suppress error messages while probing if SB_SILENT is set */ 12668c2ecf20Sopenharmony_ci c->probing = !!(c->vfs_sb->s_flags & SB_SILENT); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci err = init_constants_early(c); 12698c2ecf20Sopenharmony_ci if (err) 12708c2ecf20Sopenharmony_ci return err; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci err = ubifs_debugging_init(c); 12738c2ecf20Sopenharmony_ci if (err) 12748c2ecf20Sopenharmony_ci return err; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci err = check_volume_empty(c); 12778c2ecf20Sopenharmony_ci if (err) 12788c2ecf20Sopenharmony_ci goto out_free; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci if (c->empty && (c->ro_mount || c->ro_media)) { 12818c2ecf20Sopenharmony_ci /* 12828c2ecf20Sopenharmony_ci * This UBI volume is empty, and read-only, or the file system 12838c2ecf20Sopenharmony_ci * is mounted read-only - we cannot format it. 12848c2ecf20Sopenharmony_ci */ 12858c2ecf20Sopenharmony_ci ubifs_err(c, "can't format empty UBI volume: read-only %s", 12868c2ecf20Sopenharmony_ci c->ro_media ? "UBI volume" : "mount"); 12878c2ecf20Sopenharmony_ci err = -EROFS; 12888c2ecf20Sopenharmony_ci goto out_free; 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (c->ro_media && !c->ro_mount) { 12928c2ecf20Sopenharmony_ci ubifs_err(c, "cannot mount read-write - read-only media"); 12938c2ecf20Sopenharmony_ci err = -EROFS; 12948c2ecf20Sopenharmony_ci goto out_free; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci /* 12988c2ecf20Sopenharmony_ci * The requirement for the buffer is that it should fit indexing B-tree 12998c2ecf20Sopenharmony_ci * height amount of integers. We assume the height if the TNC tree will 13008c2ecf20Sopenharmony_ci * never exceed 64. 13018c2ecf20Sopenharmony_ci */ 13028c2ecf20Sopenharmony_ci err = -ENOMEM; 13038c2ecf20Sopenharmony_ci c->bottom_up_buf = kmalloc_array(BOTTOM_UP_HEIGHT, sizeof(int), 13048c2ecf20Sopenharmony_ci GFP_KERNEL); 13058c2ecf20Sopenharmony_ci if (!c->bottom_up_buf) 13068c2ecf20Sopenharmony_ci goto out_free; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci c->sbuf = vmalloc(c->leb_size); 13098c2ecf20Sopenharmony_ci if (!c->sbuf) 13108c2ecf20Sopenharmony_ci goto out_free; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci if (!c->ro_mount) { 13138c2ecf20Sopenharmony_ci c->ileb_buf = vmalloc(c->leb_size); 13148c2ecf20Sopenharmony_ci if (!c->ileb_buf) 13158c2ecf20Sopenharmony_ci goto out_free; 13168c2ecf20Sopenharmony_ci } 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci if (c->bulk_read == 1) 13198c2ecf20Sopenharmony_ci bu_init(c); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci if (!c->ro_mount) { 13228c2ecf20Sopenharmony_ci c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \ 13238c2ecf20Sopenharmony_ci UBIFS_CIPHER_BLOCK_SIZE, 13248c2ecf20Sopenharmony_ci GFP_KERNEL); 13258c2ecf20Sopenharmony_ci if (!c->write_reserve_buf) 13268c2ecf20Sopenharmony_ci goto out_free; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci c->mounting = 1; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (c->auth_key_name) { 13328c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) { 13338c2ecf20Sopenharmony_ci err = ubifs_init_authentication(c); 13348c2ecf20Sopenharmony_ci if (err) 13358c2ecf20Sopenharmony_ci goto out_free; 13368c2ecf20Sopenharmony_ci } else { 13378c2ecf20Sopenharmony_ci ubifs_err(c, "auth_key_name, but UBIFS is built without" 13388c2ecf20Sopenharmony_ci " authentication support"); 13398c2ecf20Sopenharmony_ci err = -EINVAL; 13408c2ecf20Sopenharmony_ci goto out_free; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci } 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci err = ubifs_read_superblock(c); 13458c2ecf20Sopenharmony_ci if (err) 13468c2ecf20Sopenharmony_ci goto out_auth; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci c->probing = 0; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci /* 13518c2ecf20Sopenharmony_ci * Make sure the compressor which is set as default in the superblock 13528c2ecf20Sopenharmony_ci * or overridden by mount options is actually compiled in. 13538c2ecf20Sopenharmony_ci */ 13548c2ecf20Sopenharmony_ci if (!ubifs_compr_present(c, c->default_compr)) { 13558c2ecf20Sopenharmony_ci ubifs_err(c, "'compressor \"%s\" is not compiled in", 13568c2ecf20Sopenharmony_ci ubifs_compr_name(c, c->default_compr)); 13578c2ecf20Sopenharmony_ci err = -ENOTSUPP; 13588c2ecf20Sopenharmony_ci goto out_auth; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci err = init_constants_sb(c); 13628c2ecf20Sopenharmony_ci if (err) 13638c2ecf20Sopenharmony_ci goto out_auth; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci sz = ALIGN(c->max_idx_node_sz, c->min_io_size) * 2; 13668c2ecf20Sopenharmony_ci c->cbuf = kmalloc(sz, GFP_NOFS); 13678c2ecf20Sopenharmony_ci if (!c->cbuf) { 13688c2ecf20Sopenharmony_ci err = -ENOMEM; 13698c2ecf20Sopenharmony_ci goto out_auth; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci err = alloc_wbufs(c); 13738c2ecf20Sopenharmony_ci if (err) 13748c2ecf20Sopenharmony_ci goto out_cbuf; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id); 13778c2ecf20Sopenharmony_ci if (!c->ro_mount) { 13788c2ecf20Sopenharmony_ci /* Create background thread */ 13798c2ecf20Sopenharmony_ci c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 13808c2ecf20Sopenharmony_ci if (IS_ERR(c->bgt)) { 13818c2ecf20Sopenharmony_ci err = PTR_ERR(c->bgt); 13828c2ecf20Sopenharmony_ci c->bgt = NULL; 13838c2ecf20Sopenharmony_ci ubifs_err(c, "cannot spawn \"%s\", error %d", 13848c2ecf20Sopenharmony_ci c->bgt_name, err); 13858c2ecf20Sopenharmony_ci goto out_wbufs; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci wake_up_process(c->bgt); 13888c2ecf20Sopenharmony_ci } 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci err = ubifs_read_master(c); 13918c2ecf20Sopenharmony_ci if (err) 13928c2ecf20Sopenharmony_ci goto out_master; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci init_constants_master(c); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) { 13978c2ecf20Sopenharmony_ci ubifs_msg(c, "recovery needed"); 13988c2ecf20Sopenharmony_ci c->need_recovery = 1; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (c->need_recovery && !c->ro_mount) { 14028c2ecf20Sopenharmony_ci err = ubifs_recover_inl_heads(c, c->sbuf); 14038c2ecf20Sopenharmony_ci if (err) 14048c2ecf20Sopenharmony_ci goto out_master; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci err = ubifs_lpt_init(c, 1, !c->ro_mount); 14088c2ecf20Sopenharmony_ci if (err) 14098c2ecf20Sopenharmony_ci goto out_master; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (!c->ro_mount && c->space_fixup) { 14128c2ecf20Sopenharmony_ci err = ubifs_fixup_free_space(c); 14138c2ecf20Sopenharmony_ci if (err) 14148c2ecf20Sopenharmony_ci goto out_lpt; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci if (!c->ro_mount && !c->need_recovery) { 14188c2ecf20Sopenharmony_ci /* 14198c2ecf20Sopenharmony_ci * Set the "dirty" flag so that if we reboot uncleanly we 14208c2ecf20Sopenharmony_ci * will notice this immediately on the next mount. 14218c2ecf20Sopenharmony_ci */ 14228c2ecf20Sopenharmony_ci c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); 14238c2ecf20Sopenharmony_ci err = ubifs_write_master(c); 14248c2ecf20Sopenharmony_ci if (err) 14258c2ecf20Sopenharmony_ci goto out_lpt; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci /* 14298c2ecf20Sopenharmony_ci * Handle offline signed images: Now that the master node is 14308c2ecf20Sopenharmony_ci * written and its validation no longer depends on the hash 14318c2ecf20Sopenharmony_ci * in the superblock, we can update the offline signed 14328c2ecf20Sopenharmony_ci * superblock with a HMAC version, 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_ci if (ubifs_authenticated(c) && ubifs_hmac_zero(c, c->sup_node->hmac)) { 14358c2ecf20Sopenharmony_ci err = ubifs_hmac_wkm(c, c->sup_node->hmac_wkm); 14368c2ecf20Sopenharmony_ci if (err) 14378c2ecf20Sopenharmony_ci goto out_lpt; 14388c2ecf20Sopenharmony_ci c->superblock_need_write = 1; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci if (!c->ro_mount && c->superblock_need_write) { 14428c2ecf20Sopenharmony_ci err = ubifs_write_sb_node(c, c->sup_node); 14438c2ecf20Sopenharmony_ci if (err) 14448c2ecf20Sopenharmony_ci goto out_lpt; 14458c2ecf20Sopenharmony_ci c->superblock_need_write = 0; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci err = dbg_check_idx_size(c, c->bi.old_idx_sz); 14498c2ecf20Sopenharmony_ci if (err) 14508c2ecf20Sopenharmony_ci goto out_lpt; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci err = ubifs_replay_journal(c); 14538c2ecf20Sopenharmony_ci if (err) 14548c2ecf20Sopenharmony_ci goto out_journal; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* Calculate 'min_idx_lebs' after journal replay */ 14578c2ecf20Sopenharmony_ci c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c); 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount); 14608c2ecf20Sopenharmony_ci if (err) 14618c2ecf20Sopenharmony_ci goto out_orphans; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (!c->ro_mount) { 14648c2ecf20Sopenharmony_ci int lnum; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci err = check_free_space(c); 14678c2ecf20Sopenharmony_ci if (err) 14688c2ecf20Sopenharmony_ci goto out_orphans; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* Check for enough log space */ 14718c2ecf20Sopenharmony_ci lnum = c->lhead_lnum + 1; 14728c2ecf20Sopenharmony_ci if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) 14738c2ecf20Sopenharmony_ci lnum = UBIFS_LOG_LNUM; 14748c2ecf20Sopenharmony_ci if (lnum == c->ltail_lnum) { 14758c2ecf20Sopenharmony_ci err = ubifs_consolidate_log(c); 14768c2ecf20Sopenharmony_ci if (err) 14778c2ecf20Sopenharmony_ci goto out_orphans; 14788c2ecf20Sopenharmony_ci } 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (c->need_recovery) { 14818c2ecf20Sopenharmony_ci if (!ubifs_authenticated(c)) { 14828c2ecf20Sopenharmony_ci err = ubifs_recover_size(c, true); 14838c2ecf20Sopenharmony_ci if (err) 14848c2ecf20Sopenharmony_ci goto out_orphans; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci err = ubifs_rcvry_gc_commit(c); 14888c2ecf20Sopenharmony_ci if (err) 14898c2ecf20Sopenharmony_ci goto out_orphans; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (ubifs_authenticated(c)) { 14928c2ecf20Sopenharmony_ci err = ubifs_recover_size(c, false); 14938c2ecf20Sopenharmony_ci if (err) 14948c2ecf20Sopenharmony_ci goto out_orphans; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci } else { 14978c2ecf20Sopenharmony_ci err = take_gc_lnum(c); 14988c2ecf20Sopenharmony_ci if (err) 14998c2ecf20Sopenharmony_ci goto out_orphans; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* 15028c2ecf20Sopenharmony_ci * GC LEB may contain garbage if there was an unclean 15038c2ecf20Sopenharmony_ci * reboot, and it should be un-mapped. 15048c2ecf20Sopenharmony_ci */ 15058c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, c->gc_lnum); 15068c2ecf20Sopenharmony_ci if (err) 15078c2ecf20Sopenharmony_ci goto out_orphans; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci err = dbg_check_lprops(c); 15118c2ecf20Sopenharmony_ci if (err) 15128c2ecf20Sopenharmony_ci goto out_orphans; 15138c2ecf20Sopenharmony_ci } else if (c->need_recovery) { 15148c2ecf20Sopenharmony_ci err = ubifs_recover_size(c, false); 15158c2ecf20Sopenharmony_ci if (err) 15168c2ecf20Sopenharmony_ci goto out_orphans; 15178c2ecf20Sopenharmony_ci } else { 15188c2ecf20Sopenharmony_ci /* 15198c2ecf20Sopenharmony_ci * Even if we mount read-only, we have to set space in GC LEB 15208c2ecf20Sopenharmony_ci * to proper value because this affects UBIFS free space 15218c2ecf20Sopenharmony_ci * reporting. We do not want to have a situation when 15228c2ecf20Sopenharmony_ci * re-mounting from R/O to R/W changes amount of free space. 15238c2ecf20Sopenharmony_ci */ 15248c2ecf20Sopenharmony_ci err = take_gc_lnum(c); 15258c2ecf20Sopenharmony_ci if (err) 15268c2ecf20Sopenharmony_ci goto out_orphans; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci spin_lock(&ubifs_infos_lock); 15308c2ecf20Sopenharmony_ci list_add_tail(&c->infos_list, &ubifs_infos); 15318c2ecf20Sopenharmony_ci spin_unlock(&ubifs_infos_lock); 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (c->need_recovery) { 15348c2ecf20Sopenharmony_ci if (c->ro_mount) 15358c2ecf20Sopenharmony_ci ubifs_msg(c, "recovery deferred"); 15368c2ecf20Sopenharmony_ci else { 15378c2ecf20Sopenharmony_ci c->need_recovery = 0; 15388c2ecf20Sopenharmony_ci ubifs_msg(c, "recovery completed"); 15398c2ecf20Sopenharmony_ci /* 15408c2ecf20Sopenharmony_ci * GC LEB has to be empty and taken at this point. But 15418c2ecf20Sopenharmony_ci * the journal head LEBs may also be accounted as 15428c2ecf20Sopenharmony_ci * "empty taken" if they are empty. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_ci ubifs_assert(c, c->lst.taken_empty_lebs > 0); 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci } else 15478c2ecf20Sopenharmony_ci ubifs_assert(c, c->lst.taken_empty_lebs > 0); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci err = dbg_check_filesystem(c); 15508c2ecf20Sopenharmony_ci if (err) 15518c2ecf20Sopenharmony_ci goto out_infos; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci dbg_debugfs_init_fs(c); 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci c->mounting = 0; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci ubifs_msg(c, "UBIFS: mounted UBI device %d, volume %d, name \"%s\"%s", 15588c2ecf20Sopenharmony_ci c->vi.ubi_num, c->vi.vol_id, c->vi.name, 15598c2ecf20Sopenharmony_ci c->ro_mount ? ", R/O mode" : ""); 15608c2ecf20Sopenharmony_ci x = (long long)c->main_lebs * c->leb_size; 15618c2ecf20Sopenharmony_ci y = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes; 15628c2ecf20Sopenharmony_ci ubifs_msg(c, "LEB size: %d bytes (%d KiB), min./max. I/O unit sizes: %d bytes/%d bytes", 15638c2ecf20Sopenharmony_ci c->leb_size, c->leb_size >> 10, c->min_io_size, 15648c2ecf20Sopenharmony_ci c->max_write_size); 15658c2ecf20Sopenharmony_ci ubifs_msg(c, "FS size: %lld bytes (%lld MiB, %d LEBs), journal size %lld bytes (%lld MiB, %d LEBs)", 15668c2ecf20Sopenharmony_ci x, x >> 20, c->main_lebs, 15678c2ecf20Sopenharmony_ci y, y >> 20, c->log_lebs + c->max_bud_cnt); 15688c2ecf20Sopenharmony_ci ubifs_msg(c, "reserved for root: %llu bytes (%llu KiB)", 15698c2ecf20Sopenharmony_ci c->report_rp_size, c->report_rp_size >> 10); 15708c2ecf20Sopenharmony_ci ubifs_msg(c, "media format: w%d/r%d (latest is w%d/r%d), UUID %pUB%s", 15718c2ecf20Sopenharmony_ci c->fmt_version, c->ro_compat_version, 15728c2ecf20Sopenharmony_ci UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION, c->uuid, 15738c2ecf20Sopenharmony_ci c->big_lpt ? ", big LPT model" : ", small LPT model"); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci dbg_gen("default compressor: %s", ubifs_compr_name(c, c->default_compr)); 15768c2ecf20Sopenharmony_ci dbg_gen("data journal heads: %d", 15778c2ecf20Sopenharmony_ci c->jhead_cnt - NONDATA_JHEADS_CNT); 15788c2ecf20Sopenharmony_ci dbg_gen("log LEBs: %d (%d - %d)", 15798c2ecf20Sopenharmony_ci c->log_lebs, UBIFS_LOG_LNUM, c->log_last); 15808c2ecf20Sopenharmony_ci dbg_gen("LPT area LEBs: %d (%d - %d)", 15818c2ecf20Sopenharmony_ci c->lpt_lebs, c->lpt_first, c->lpt_last); 15828c2ecf20Sopenharmony_ci dbg_gen("orphan area LEBs: %d (%d - %d)", 15838c2ecf20Sopenharmony_ci c->orph_lebs, c->orph_first, c->orph_last); 15848c2ecf20Sopenharmony_ci dbg_gen("main area LEBs: %d (%d - %d)", 15858c2ecf20Sopenharmony_ci c->main_lebs, c->main_first, c->leb_cnt - 1); 15868c2ecf20Sopenharmony_ci dbg_gen("index LEBs: %d", c->lst.idx_lebs); 15878c2ecf20Sopenharmony_ci dbg_gen("total index bytes: %lld (%lld KiB, %lld MiB)", 15888c2ecf20Sopenharmony_ci c->bi.old_idx_sz, c->bi.old_idx_sz >> 10, 15898c2ecf20Sopenharmony_ci c->bi.old_idx_sz >> 20); 15908c2ecf20Sopenharmony_ci dbg_gen("key hash type: %d", c->key_hash_type); 15918c2ecf20Sopenharmony_ci dbg_gen("tree fanout: %d", c->fanout); 15928c2ecf20Sopenharmony_ci dbg_gen("reserved GC LEB: %d", c->gc_lnum); 15938c2ecf20Sopenharmony_ci dbg_gen("max. znode size %d", c->max_znode_sz); 15948c2ecf20Sopenharmony_ci dbg_gen("max. index node size %d", c->max_idx_node_sz); 15958c2ecf20Sopenharmony_ci dbg_gen("node sizes: data %zu, inode %zu, dentry %zu", 15968c2ecf20Sopenharmony_ci UBIFS_DATA_NODE_SZ, UBIFS_INO_NODE_SZ, UBIFS_DENT_NODE_SZ); 15978c2ecf20Sopenharmony_ci dbg_gen("node sizes: trun %zu, sb %zu, master %zu", 15988c2ecf20Sopenharmony_ci UBIFS_TRUN_NODE_SZ, UBIFS_SB_NODE_SZ, UBIFS_MST_NODE_SZ); 15998c2ecf20Sopenharmony_ci dbg_gen("node sizes: ref %zu, cmt. start %zu, orph %zu", 16008c2ecf20Sopenharmony_ci UBIFS_REF_NODE_SZ, UBIFS_CS_NODE_SZ, UBIFS_ORPH_NODE_SZ); 16018c2ecf20Sopenharmony_ci dbg_gen("max. node sizes: data %zu, inode %zu dentry %zu, idx %d", 16028c2ecf20Sopenharmony_ci UBIFS_MAX_DATA_NODE_SZ, UBIFS_MAX_INO_NODE_SZ, 16038c2ecf20Sopenharmony_ci UBIFS_MAX_DENT_NODE_SZ, ubifs_idx_node_sz(c, c->fanout)); 16048c2ecf20Sopenharmony_ci dbg_gen("dead watermark: %d", c->dead_wm); 16058c2ecf20Sopenharmony_ci dbg_gen("dark watermark: %d", c->dark_wm); 16068c2ecf20Sopenharmony_ci dbg_gen("LEB overhead: %d", c->leb_overhead); 16078c2ecf20Sopenharmony_ci x = (long long)c->main_lebs * c->dark_wm; 16088c2ecf20Sopenharmony_ci dbg_gen("max. dark space: %lld (%lld KiB, %lld MiB)", 16098c2ecf20Sopenharmony_ci x, x >> 10, x >> 20); 16108c2ecf20Sopenharmony_ci dbg_gen("maximum bud bytes: %lld (%lld KiB, %lld MiB)", 16118c2ecf20Sopenharmony_ci c->max_bud_bytes, c->max_bud_bytes >> 10, 16128c2ecf20Sopenharmony_ci c->max_bud_bytes >> 20); 16138c2ecf20Sopenharmony_ci dbg_gen("BG commit bud bytes: %lld (%lld KiB, %lld MiB)", 16148c2ecf20Sopenharmony_ci c->bg_bud_bytes, c->bg_bud_bytes >> 10, 16158c2ecf20Sopenharmony_ci c->bg_bud_bytes >> 20); 16168c2ecf20Sopenharmony_ci dbg_gen("current bud bytes %lld (%lld KiB, %lld MiB)", 16178c2ecf20Sopenharmony_ci c->bud_bytes, c->bud_bytes >> 10, c->bud_bytes >> 20); 16188c2ecf20Sopenharmony_ci dbg_gen("max. seq. number: %llu", c->max_sqnum); 16198c2ecf20Sopenharmony_ci dbg_gen("commit number: %llu", c->cmt_no); 16208c2ecf20Sopenharmony_ci dbg_gen("max. xattrs per inode: %d", ubifs_xattr_max_cnt(c)); 16218c2ecf20Sopenharmony_ci dbg_gen("max orphans: %d", c->max_orphans); 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci return 0; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ciout_infos: 16268c2ecf20Sopenharmony_ci spin_lock(&ubifs_infos_lock); 16278c2ecf20Sopenharmony_ci list_del(&c->infos_list); 16288c2ecf20Sopenharmony_ci spin_unlock(&ubifs_infos_lock); 16298c2ecf20Sopenharmony_ciout_orphans: 16308c2ecf20Sopenharmony_ci free_orphans(c); 16318c2ecf20Sopenharmony_ciout_journal: 16328c2ecf20Sopenharmony_ci destroy_journal(c); 16338c2ecf20Sopenharmony_ciout_lpt: 16348c2ecf20Sopenharmony_ci ubifs_lpt_free(c, 0); 16358c2ecf20Sopenharmony_ciout_master: 16368c2ecf20Sopenharmony_ci kfree(c->mst_node); 16378c2ecf20Sopenharmony_ci kfree(c->rcvrd_mst_node); 16388c2ecf20Sopenharmony_ci if (c->bgt) 16398c2ecf20Sopenharmony_ci kthread_stop(c->bgt); 16408c2ecf20Sopenharmony_ciout_wbufs: 16418c2ecf20Sopenharmony_ci free_wbufs(c); 16428c2ecf20Sopenharmony_ciout_cbuf: 16438c2ecf20Sopenharmony_ci kfree(c->cbuf); 16448c2ecf20Sopenharmony_ciout_auth: 16458c2ecf20Sopenharmony_ci ubifs_exit_authentication(c); 16468c2ecf20Sopenharmony_ciout_free: 16478c2ecf20Sopenharmony_ci kfree(c->write_reserve_buf); 16488c2ecf20Sopenharmony_ci kfree(c->bu.buf); 16498c2ecf20Sopenharmony_ci vfree(c->ileb_buf); 16508c2ecf20Sopenharmony_ci vfree(c->sbuf); 16518c2ecf20Sopenharmony_ci kfree(c->bottom_up_buf); 16528c2ecf20Sopenharmony_ci kfree(c->sup_node); 16538c2ecf20Sopenharmony_ci ubifs_debugging_exit(c); 16548c2ecf20Sopenharmony_ci return err; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci/** 16588c2ecf20Sopenharmony_ci * ubifs_umount - un-mount UBIFS file-system. 16598c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 16608c2ecf20Sopenharmony_ci * 16618c2ecf20Sopenharmony_ci * Note, this function is called to free allocated resourced when un-mounting, 16628c2ecf20Sopenharmony_ci * as well as free resources when an error occurred while we were half way 16638c2ecf20Sopenharmony_ci * through mounting (error path cleanup function). So it has to make sure the 16648c2ecf20Sopenharmony_ci * resource was actually allocated before freeing it. 16658c2ecf20Sopenharmony_ci */ 16668c2ecf20Sopenharmony_cistatic void ubifs_umount(struct ubifs_info *c) 16678c2ecf20Sopenharmony_ci{ 16688c2ecf20Sopenharmony_ci dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num, 16698c2ecf20Sopenharmony_ci c->vi.vol_id); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci dbg_debugfs_exit_fs(c); 16728c2ecf20Sopenharmony_ci spin_lock(&ubifs_infos_lock); 16738c2ecf20Sopenharmony_ci list_del(&c->infos_list); 16748c2ecf20Sopenharmony_ci spin_unlock(&ubifs_infos_lock); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (c->bgt) 16778c2ecf20Sopenharmony_ci kthread_stop(c->bgt); 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci destroy_journal(c); 16808c2ecf20Sopenharmony_ci free_wbufs(c); 16818c2ecf20Sopenharmony_ci free_orphans(c); 16828c2ecf20Sopenharmony_ci ubifs_lpt_free(c, 0); 16838c2ecf20Sopenharmony_ci ubifs_exit_authentication(c); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci ubifs_release_options(c); 16868c2ecf20Sopenharmony_ci kfree(c->cbuf); 16878c2ecf20Sopenharmony_ci kfree(c->rcvrd_mst_node); 16888c2ecf20Sopenharmony_ci kfree(c->mst_node); 16898c2ecf20Sopenharmony_ci kfree(c->write_reserve_buf); 16908c2ecf20Sopenharmony_ci kfree(c->bu.buf); 16918c2ecf20Sopenharmony_ci vfree(c->ileb_buf); 16928c2ecf20Sopenharmony_ci vfree(c->sbuf); 16938c2ecf20Sopenharmony_ci kfree(c->bottom_up_buf); 16948c2ecf20Sopenharmony_ci kfree(c->sup_node); 16958c2ecf20Sopenharmony_ci ubifs_debugging_exit(c); 16968c2ecf20Sopenharmony_ci} 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci/** 16998c2ecf20Sopenharmony_ci * ubifs_remount_rw - re-mount in read-write mode. 17008c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 17018c2ecf20Sopenharmony_ci * 17028c2ecf20Sopenharmony_ci * UBIFS avoids allocating many unnecessary resources when mounted in read-only 17038c2ecf20Sopenharmony_ci * mode. This function allocates the needed resources and re-mounts UBIFS in 17048c2ecf20Sopenharmony_ci * read-write mode. 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_cistatic int ubifs_remount_rw(struct ubifs_info *c) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci int err, lnum; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (c->rw_incompat) { 17118c2ecf20Sopenharmony_ci ubifs_err(c, "the file-system is not R/W-compatible"); 17128c2ecf20Sopenharmony_ci ubifs_msg(c, "on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d", 17138c2ecf20Sopenharmony_ci c->fmt_version, c->ro_compat_version, 17148c2ecf20Sopenharmony_ci UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION); 17158c2ecf20Sopenharmony_ci return -EROFS; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci mutex_lock(&c->umount_mutex); 17198c2ecf20Sopenharmony_ci dbg_save_space_info(c); 17208c2ecf20Sopenharmony_ci c->remounting_rw = 1; 17218c2ecf20Sopenharmony_ci c->ro_mount = 0; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci if (c->space_fixup) { 17248c2ecf20Sopenharmony_ci err = ubifs_fixup_free_space(c); 17258c2ecf20Sopenharmony_ci if (err) 17268c2ecf20Sopenharmony_ci goto out; 17278c2ecf20Sopenharmony_ci } 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci err = check_free_space(c); 17308c2ecf20Sopenharmony_ci if (err) 17318c2ecf20Sopenharmony_ci goto out; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (c->need_recovery) { 17348c2ecf20Sopenharmony_ci ubifs_msg(c, "completing deferred recovery"); 17358c2ecf20Sopenharmony_ci err = ubifs_write_rcvrd_mst_node(c); 17368c2ecf20Sopenharmony_ci if (err) 17378c2ecf20Sopenharmony_ci goto out; 17388c2ecf20Sopenharmony_ci if (!ubifs_authenticated(c)) { 17398c2ecf20Sopenharmony_ci err = ubifs_recover_size(c, true); 17408c2ecf20Sopenharmony_ci if (err) 17418c2ecf20Sopenharmony_ci goto out; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci err = ubifs_clean_lebs(c, c->sbuf); 17448c2ecf20Sopenharmony_ci if (err) 17458c2ecf20Sopenharmony_ci goto out; 17468c2ecf20Sopenharmony_ci err = ubifs_recover_inl_heads(c, c->sbuf); 17478c2ecf20Sopenharmony_ci if (err) 17488c2ecf20Sopenharmony_ci goto out; 17498c2ecf20Sopenharmony_ci } else { 17508c2ecf20Sopenharmony_ci /* A readonly mount is not allowed to have orphans */ 17518c2ecf20Sopenharmony_ci ubifs_assert(c, c->tot_orphans == 0); 17528c2ecf20Sopenharmony_ci err = ubifs_clear_orphans(c); 17538c2ecf20Sopenharmony_ci if (err) 17548c2ecf20Sopenharmony_ci goto out; 17558c2ecf20Sopenharmony_ci } 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) { 17588c2ecf20Sopenharmony_ci c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY); 17598c2ecf20Sopenharmony_ci err = ubifs_write_master(c); 17608c2ecf20Sopenharmony_ci if (err) 17618c2ecf20Sopenharmony_ci goto out; 17628c2ecf20Sopenharmony_ci } 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (c->superblock_need_write) { 17658c2ecf20Sopenharmony_ci struct ubifs_sb_node *sup = c->sup_node; 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci err = ubifs_write_sb_node(c, sup); 17688c2ecf20Sopenharmony_ci if (err) 17698c2ecf20Sopenharmony_ci goto out; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci c->superblock_need_write = 0; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci c->ileb_buf = vmalloc(c->leb_size); 17758c2ecf20Sopenharmony_ci if (!c->ileb_buf) { 17768c2ecf20Sopenharmony_ci err = -ENOMEM; 17778c2ecf20Sopenharmony_ci goto out; 17788c2ecf20Sopenharmony_ci } 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \ 17818c2ecf20Sopenharmony_ci UBIFS_CIPHER_BLOCK_SIZE, GFP_KERNEL); 17828c2ecf20Sopenharmony_ci if (!c->write_reserve_buf) { 17838c2ecf20Sopenharmony_ci err = -ENOMEM; 17848c2ecf20Sopenharmony_ci goto out; 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_ci err = ubifs_lpt_init(c, 0, 1); 17888c2ecf20Sopenharmony_ci if (err) 17898c2ecf20Sopenharmony_ci goto out; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci /* Create background thread */ 17928c2ecf20Sopenharmony_ci c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name); 17938c2ecf20Sopenharmony_ci if (IS_ERR(c->bgt)) { 17948c2ecf20Sopenharmony_ci err = PTR_ERR(c->bgt); 17958c2ecf20Sopenharmony_ci c->bgt = NULL; 17968c2ecf20Sopenharmony_ci ubifs_err(c, "cannot spawn \"%s\", error %d", 17978c2ecf20Sopenharmony_ci c->bgt_name, err); 17988c2ecf20Sopenharmony_ci goto out; 17998c2ecf20Sopenharmony_ci } 18008c2ecf20Sopenharmony_ci wake_up_process(c->bgt); 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci c->orph_buf = vmalloc(c->leb_size); 18038c2ecf20Sopenharmony_ci if (!c->orph_buf) { 18048c2ecf20Sopenharmony_ci err = -ENOMEM; 18058c2ecf20Sopenharmony_ci goto out; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci /* Check for enough log space */ 18098c2ecf20Sopenharmony_ci lnum = c->lhead_lnum + 1; 18108c2ecf20Sopenharmony_ci if (lnum >= UBIFS_LOG_LNUM + c->log_lebs) 18118c2ecf20Sopenharmony_ci lnum = UBIFS_LOG_LNUM; 18128c2ecf20Sopenharmony_ci if (lnum == c->ltail_lnum) { 18138c2ecf20Sopenharmony_ci err = ubifs_consolidate_log(c); 18148c2ecf20Sopenharmony_ci if (err) 18158c2ecf20Sopenharmony_ci goto out; 18168c2ecf20Sopenharmony_ci } 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (c->need_recovery) { 18198c2ecf20Sopenharmony_ci err = ubifs_rcvry_gc_commit(c); 18208c2ecf20Sopenharmony_ci if (err) 18218c2ecf20Sopenharmony_ci goto out; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (ubifs_authenticated(c)) { 18248c2ecf20Sopenharmony_ci err = ubifs_recover_size(c, false); 18258c2ecf20Sopenharmony_ci if (err) 18268c2ecf20Sopenharmony_ci goto out; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci } else { 18298c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, c->gc_lnum); 18308c2ecf20Sopenharmony_ci } 18318c2ecf20Sopenharmony_ci if (err) 18328c2ecf20Sopenharmony_ci goto out; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci dbg_gen("re-mounted read-write"); 18358c2ecf20Sopenharmony_ci c->remounting_rw = 0; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci if (c->need_recovery) { 18388c2ecf20Sopenharmony_ci c->need_recovery = 0; 18398c2ecf20Sopenharmony_ci ubifs_msg(c, "deferred recovery completed"); 18408c2ecf20Sopenharmony_ci } else { 18418c2ecf20Sopenharmony_ci /* 18428c2ecf20Sopenharmony_ci * Do not run the debugging space check if the were doing 18438c2ecf20Sopenharmony_ci * recovery, because when we saved the information we had the 18448c2ecf20Sopenharmony_ci * file-system in a state where the TNC and lprops has been 18458c2ecf20Sopenharmony_ci * modified in memory, but all the I/O operations (including a 18468c2ecf20Sopenharmony_ci * commit) were deferred. So the file-system was in 18478c2ecf20Sopenharmony_ci * "non-committed" state. Now the file-system is in committed 18488c2ecf20Sopenharmony_ci * state, and of course the amount of free space will change 18498c2ecf20Sopenharmony_ci * because, for example, the old index size was imprecise. 18508c2ecf20Sopenharmony_ci */ 18518c2ecf20Sopenharmony_ci err = dbg_check_space_info(c); 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci mutex_unlock(&c->umount_mutex); 18558c2ecf20Sopenharmony_ci return err; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ciout: 18588c2ecf20Sopenharmony_ci c->ro_mount = 1; 18598c2ecf20Sopenharmony_ci vfree(c->orph_buf); 18608c2ecf20Sopenharmony_ci c->orph_buf = NULL; 18618c2ecf20Sopenharmony_ci if (c->bgt) { 18628c2ecf20Sopenharmony_ci kthread_stop(c->bgt); 18638c2ecf20Sopenharmony_ci c->bgt = NULL; 18648c2ecf20Sopenharmony_ci } 18658c2ecf20Sopenharmony_ci kfree(c->write_reserve_buf); 18668c2ecf20Sopenharmony_ci c->write_reserve_buf = NULL; 18678c2ecf20Sopenharmony_ci vfree(c->ileb_buf); 18688c2ecf20Sopenharmony_ci c->ileb_buf = NULL; 18698c2ecf20Sopenharmony_ci ubifs_lpt_free(c, 1); 18708c2ecf20Sopenharmony_ci c->remounting_rw = 0; 18718c2ecf20Sopenharmony_ci mutex_unlock(&c->umount_mutex); 18728c2ecf20Sopenharmony_ci return err; 18738c2ecf20Sopenharmony_ci} 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci/** 18768c2ecf20Sopenharmony_ci * ubifs_remount_ro - re-mount in read-only mode. 18778c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 18788c2ecf20Sopenharmony_ci * 18798c2ecf20Sopenharmony_ci * We assume VFS has stopped writing. Possibly the background thread could be 18808c2ecf20Sopenharmony_ci * running a commit, however kthread_stop will wait in that case. 18818c2ecf20Sopenharmony_ci */ 18828c2ecf20Sopenharmony_cistatic void ubifs_remount_ro(struct ubifs_info *c) 18838c2ecf20Sopenharmony_ci{ 18848c2ecf20Sopenharmony_ci int i, err; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci ubifs_assert(c, !c->need_recovery); 18878c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_mount); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci mutex_lock(&c->umount_mutex); 18908c2ecf20Sopenharmony_ci if (c->bgt) { 18918c2ecf20Sopenharmony_ci kthread_stop(c->bgt); 18928c2ecf20Sopenharmony_ci c->bgt = NULL; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci dbg_save_space_info(c); 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 18988c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync(&c->jheads[i].wbuf); 18998c2ecf20Sopenharmony_ci if (err) 19008c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); 19048c2ecf20Sopenharmony_ci c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); 19058c2ecf20Sopenharmony_ci c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); 19068c2ecf20Sopenharmony_ci err = ubifs_write_master(c); 19078c2ecf20Sopenharmony_ci if (err) 19088c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci vfree(c->orph_buf); 19118c2ecf20Sopenharmony_ci c->orph_buf = NULL; 19128c2ecf20Sopenharmony_ci kfree(c->write_reserve_buf); 19138c2ecf20Sopenharmony_ci c->write_reserve_buf = NULL; 19148c2ecf20Sopenharmony_ci vfree(c->ileb_buf); 19158c2ecf20Sopenharmony_ci c->ileb_buf = NULL; 19168c2ecf20Sopenharmony_ci ubifs_lpt_free(c, 1); 19178c2ecf20Sopenharmony_ci c->ro_mount = 1; 19188c2ecf20Sopenharmony_ci err = dbg_check_space_info(c); 19198c2ecf20Sopenharmony_ci if (err) 19208c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 19218c2ecf20Sopenharmony_ci mutex_unlock(&c->umount_mutex); 19228c2ecf20Sopenharmony_ci} 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_cistatic void ubifs_put_super(struct super_block *sb) 19258c2ecf20Sopenharmony_ci{ 19268c2ecf20Sopenharmony_ci int i; 19278c2ecf20Sopenharmony_ci struct ubifs_info *c = sb->s_fs_info; 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci ubifs_msg(c, "un-mount UBI device %d", c->vi.ubi_num); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* 19328c2ecf20Sopenharmony_ci * The following asserts are only valid if there has not been a failure 19338c2ecf20Sopenharmony_ci * of the media. For example, there will be dirty inodes if we failed 19348c2ecf20Sopenharmony_ci * to write them back because of I/O errors. 19358c2ecf20Sopenharmony_ci */ 19368c2ecf20Sopenharmony_ci if (!c->ro_error) { 19378c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.idx_growth == 0); 19388c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.dd_growth == 0); 19398c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.data_growth == 0); 19408c2ecf20Sopenharmony_ci } 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* 19438c2ecf20Sopenharmony_ci * The 'c->umount_lock' prevents races between UBIFS memory shrinker 19448c2ecf20Sopenharmony_ci * and file system un-mount. Namely, it prevents the shrinker from 19458c2ecf20Sopenharmony_ci * picking this superblock for shrinking - it will be just skipped if 19468c2ecf20Sopenharmony_ci * the mutex is locked. 19478c2ecf20Sopenharmony_ci */ 19488c2ecf20Sopenharmony_ci mutex_lock(&c->umount_mutex); 19498c2ecf20Sopenharmony_ci if (!c->ro_mount) { 19508c2ecf20Sopenharmony_ci /* 19518c2ecf20Sopenharmony_ci * First of all kill the background thread to make sure it does 19528c2ecf20Sopenharmony_ci * not interfere with un-mounting and freeing resources. 19538c2ecf20Sopenharmony_ci */ 19548c2ecf20Sopenharmony_ci if (c->bgt) { 19558c2ecf20Sopenharmony_ci kthread_stop(c->bgt); 19568c2ecf20Sopenharmony_ci c->bgt = NULL; 19578c2ecf20Sopenharmony_ci } 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci /* 19608c2ecf20Sopenharmony_ci * On fatal errors c->ro_error is set to 1, in which case we do 19618c2ecf20Sopenharmony_ci * not write the master node. 19628c2ecf20Sopenharmony_ci */ 19638c2ecf20Sopenharmony_ci if (!c->ro_error) { 19648c2ecf20Sopenharmony_ci int err; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci /* Synchronize write-buffers */ 19678c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 19688c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync(&c->jheads[i].wbuf); 19698c2ecf20Sopenharmony_ci if (err) 19708c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* 19748c2ecf20Sopenharmony_ci * We are being cleanly unmounted which means the 19758c2ecf20Sopenharmony_ci * orphans were killed - indicate this in the master 19768c2ecf20Sopenharmony_ci * node. Also save the reserved GC LEB number. 19778c2ecf20Sopenharmony_ci */ 19788c2ecf20Sopenharmony_ci c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); 19798c2ecf20Sopenharmony_ci c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); 19808c2ecf20Sopenharmony_ci c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum); 19818c2ecf20Sopenharmony_ci err = ubifs_write_master(c); 19828c2ecf20Sopenharmony_ci if (err) 19838c2ecf20Sopenharmony_ci /* 19848c2ecf20Sopenharmony_ci * Recovery will attempt to fix the master area 19858c2ecf20Sopenharmony_ci * next mount, so we just print a message and 19868c2ecf20Sopenharmony_ci * continue to unmount normally. 19878c2ecf20Sopenharmony_ci */ 19888c2ecf20Sopenharmony_ci ubifs_err(c, "failed to write master node, error %d", 19898c2ecf20Sopenharmony_ci err); 19908c2ecf20Sopenharmony_ci } else { 19918c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) 19928c2ecf20Sopenharmony_ci /* Make sure write-buffer timers are canceled */ 19938c2ecf20Sopenharmony_ci hrtimer_cancel(&c->jheads[i].wbuf.timer); 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci ubifs_umount(c); 19988c2ecf20Sopenharmony_ci ubi_close_volume(c->ubi); 19998c2ecf20Sopenharmony_ci mutex_unlock(&c->umount_mutex); 20008c2ecf20Sopenharmony_ci} 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_cistatic int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci int err; 20058c2ecf20Sopenharmony_ci struct ubifs_info *c = sb->s_fs_info; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci sync_filesystem(sb); 20088c2ecf20Sopenharmony_ci dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags); 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci err = ubifs_parse_options(c, data, 1); 20118c2ecf20Sopenharmony_ci if (err) { 20128c2ecf20Sopenharmony_ci ubifs_err(c, "invalid or unknown remount parameter"); 20138c2ecf20Sopenharmony_ci return err; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci if (c->ro_mount && !(*flags & SB_RDONLY)) { 20178c2ecf20Sopenharmony_ci if (c->ro_error) { 20188c2ecf20Sopenharmony_ci ubifs_msg(c, "cannot re-mount R/W due to prior errors"); 20198c2ecf20Sopenharmony_ci return -EROFS; 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci if (c->ro_media) { 20228c2ecf20Sopenharmony_ci ubifs_msg(c, "cannot re-mount R/W - UBI volume is R/O"); 20238c2ecf20Sopenharmony_ci return -EROFS; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci err = ubifs_remount_rw(c); 20268c2ecf20Sopenharmony_ci if (err) 20278c2ecf20Sopenharmony_ci return err; 20288c2ecf20Sopenharmony_ci } else if (!c->ro_mount && (*flags & SB_RDONLY)) { 20298c2ecf20Sopenharmony_ci if (c->ro_error) { 20308c2ecf20Sopenharmony_ci ubifs_msg(c, "cannot re-mount R/O due to prior errors"); 20318c2ecf20Sopenharmony_ci return -EROFS; 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci ubifs_remount_ro(c); 20348c2ecf20Sopenharmony_ci } 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (c->bulk_read == 1) 20378c2ecf20Sopenharmony_ci bu_init(c); 20388c2ecf20Sopenharmony_ci else { 20398c2ecf20Sopenharmony_ci dbg_gen("disable bulk-read"); 20408c2ecf20Sopenharmony_ci mutex_lock(&c->bu_mutex); 20418c2ecf20Sopenharmony_ci kfree(c->bu.buf); 20428c2ecf20Sopenharmony_ci c->bu.buf = NULL; 20438c2ecf20Sopenharmony_ci mutex_unlock(&c->bu_mutex); 20448c2ecf20Sopenharmony_ci } 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci if (!c->need_recovery) 20478c2ecf20Sopenharmony_ci ubifs_assert(c, c->lst.taken_empty_lebs > 0); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci return 0; 20508c2ecf20Sopenharmony_ci} 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ciconst struct super_operations ubifs_super_operations = { 20538c2ecf20Sopenharmony_ci .alloc_inode = ubifs_alloc_inode, 20548c2ecf20Sopenharmony_ci .free_inode = ubifs_free_inode, 20558c2ecf20Sopenharmony_ci .put_super = ubifs_put_super, 20568c2ecf20Sopenharmony_ci .write_inode = ubifs_write_inode, 20578c2ecf20Sopenharmony_ci .drop_inode = ubifs_drop_inode, 20588c2ecf20Sopenharmony_ci .evict_inode = ubifs_evict_inode, 20598c2ecf20Sopenharmony_ci .statfs = ubifs_statfs, 20608c2ecf20Sopenharmony_ci .dirty_inode = ubifs_dirty_inode, 20618c2ecf20Sopenharmony_ci .remount_fs = ubifs_remount_fs, 20628c2ecf20Sopenharmony_ci .show_options = ubifs_show_options, 20638c2ecf20Sopenharmony_ci .sync_fs = ubifs_sync_fs, 20648c2ecf20Sopenharmony_ci}; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci/** 20678c2ecf20Sopenharmony_ci * open_ubi - parse UBI device name string and open the UBI device. 20688c2ecf20Sopenharmony_ci * @name: UBI volume name 20698c2ecf20Sopenharmony_ci * @mode: UBI volume open mode 20708c2ecf20Sopenharmony_ci * 20718c2ecf20Sopenharmony_ci * The primary method of mounting UBIFS is by specifying the UBI volume 20728c2ecf20Sopenharmony_ci * character device node path. However, UBIFS may also be mounted withoug any 20738c2ecf20Sopenharmony_ci * character device node using one of the following methods: 20748c2ecf20Sopenharmony_ci * 20758c2ecf20Sopenharmony_ci * o ubiX_Y - mount UBI device number X, volume Y; 20768c2ecf20Sopenharmony_ci * o ubiY - mount UBI device number 0, volume Y; 20778c2ecf20Sopenharmony_ci * o ubiX:NAME - mount UBI device X, volume with name NAME; 20788c2ecf20Sopenharmony_ci * o ubi:NAME - mount UBI device 0, volume with name NAME. 20798c2ecf20Sopenharmony_ci * 20808c2ecf20Sopenharmony_ci * Alternative '!' separator may be used instead of ':' (because some shells 20818c2ecf20Sopenharmony_ci * like busybox may interpret ':' as an NFS host name separator). This function 20828c2ecf20Sopenharmony_ci * returns UBI volume description object in case of success and a negative 20838c2ecf20Sopenharmony_ci * error code in case of failure. 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_cistatic struct ubi_volume_desc *open_ubi(const char *name, int mode) 20868c2ecf20Sopenharmony_ci{ 20878c2ecf20Sopenharmony_ci struct ubi_volume_desc *ubi; 20888c2ecf20Sopenharmony_ci int dev, vol; 20898c2ecf20Sopenharmony_ci char *endptr; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci if (!name || !*name) 20928c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci /* First, try to open using the device node path method */ 20958c2ecf20Sopenharmony_ci ubi = ubi_open_volume_path(name, mode); 20968c2ecf20Sopenharmony_ci if (!IS_ERR(ubi)) 20978c2ecf20Sopenharmony_ci return ubi; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci /* Try the "nodev" method */ 21008c2ecf20Sopenharmony_ci if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i') 21018c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci /* ubi:NAME method */ 21048c2ecf20Sopenharmony_ci if ((name[3] == ':' || name[3] == '!') && name[4] != '\0') 21058c2ecf20Sopenharmony_ci return ubi_open_volume_nm(0, name + 4, mode); 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci if (!isdigit(name[3])) 21088c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci dev = simple_strtoul(name + 3, &endptr, 0); 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci /* ubiY method */ 21138c2ecf20Sopenharmony_ci if (*endptr == '\0') 21148c2ecf20Sopenharmony_ci return ubi_open_volume(0, dev, mode); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci /* ubiX_Y method */ 21178c2ecf20Sopenharmony_ci if (*endptr == '_' && isdigit(endptr[1])) { 21188c2ecf20Sopenharmony_ci vol = simple_strtoul(endptr + 1, &endptr, 0); 21198c2ecf20Sopenharmony_ci if (*endptr != '\0') 21208c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21218c2ecf20Sopenharmony_ci return ubi_open_volume(dev, vol, mode); 21228c2ecf20Sopenharmony_ci } 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci /* ubiX:NAME method */ 21258c2ecf20Sopenharmony_ci if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0') 21268c2ecf20Sopenharmony_ci return ubi_open_volume_nm(dev, ++endptr, mode); 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 21298c2ecf20Sopenharmony_ci} 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_cistatic struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi) 21328c2ecf20Sopenharmony_ci{ 21338c2ecf20Sopenharmony_ci struct ubifs_info *c; 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci c = kzalloc(sizeof(struct ubifs_info), GFP_KERNEL); 21368c2ecf20Sopenharmony_ci if (c) { 21378c2ecf20Sopenharmony_ci spin_lock_init(&c->cnt_lock); 21388c2ecf20Sopenharmony_ci spin_lock_init(&c->cs_lock); 21398c2ecf20Sopenharmony_ci spin_lock_init(&c->buds_lock); 21408c2ecf20Sopenharmony_ci spin_lock_init(&c->space_lock); 21418c2ecf20Sopenharmony_ci spin_lock_init(&c->orphan_lock); 21428c2ecf20Sopenharmony_ci init_rwsem(&c->commit_sem); 21438c2ecf20Sopenharmony_ci mutex_init(&c->lp_mutex); 21448c2ecf20Sopenharmony_ci mutex_init(&c->tnc_mutex); 21458c2ecf20Sopenharmony_ci mutex_init(&c->log_mutex); 21468c2ecf20Sopenharmony_ci mutex_init(&c->umount_mutex); 21478c2ecf20Sopenharmony_ci mutex_init(&c->bu_mutex); 21488c2ecf20Sopenharmony_ci mutex_init(&c->write_reserve_mutex); 21498c2ecf20Sopenharmony_ci init_waitqueue_head(&c->cmt_wq); 21508c2ecf20Sopenharmony_ci c->buds = RB_ROOT; 21518c2ecf20Sopenharmony_ci c->old_idx = RB_ROOT; 21528c2ecf20Sopenharmony_ci c->size_tree = RB_ROOT; 21538c2ecf20Sopenharmony_ci c->orph_tree = RB_ROOT; 21548c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->infos_list); 21558c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->idx_gc); 21568c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->replay_list); 21578c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->replay_buds); 21588c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->uncat_list); 21598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->empty_list); 21608c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->freeable_list); 21618c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->frdi_idx_list); 21628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->unclean_leb_list); 21638c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->old_buds); 21648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->orph_list); 21658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&c->orph_new); 21668c2ecf20Sopenharmony_ci c->no_chk_data_crc = 1; 21678c2ecf20Sopenharmony_ci c->assert_action = ASSACT_RO; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci c->highest_inum = UBIFS_FIRST_INO; 21708c2ecf20Sopenharmony_ci c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci ubi_get_volume_info(ubi, &c->vi); 21738c2ecf20Sopenharmony_ci ubi_get_device_info(c->vi.ubi_num, &c->di); 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci return c; 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_cistatic int ubifs_fill_super(struct super_block *sb, void *data, int silent) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci struct ubifs_info *c = sb->s_fs_info; 21818c2ecf20Sopenharmony_ci struct inode *root; 21828c2ecf20Sopenharmony_ci int err; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci c->vfs_sb = sb; 21858c2ecf20Sopenharmony_ci /* Re-open the UBI device in read-write mode */ 21868c2ecf20Sopenharmony_ci c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE); 21878c2ecf20Sopenharmony_ci if (IS_ERR(c->ubi)) { 21888c2ecf20Sopenharmony_ci err = PTR_ERR(c->ubi); 21898c2ecf20Sopenharmony_ci goto out; 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci err = ubifs_parse_options(c, data, 0); 21938c2ecf20Sopenharmony_ci if (err) 21948c2ecf20Sopenharmony_ci goto out_close; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ci /* 21978c2ecf20Sopenharmony_ci * UBIFS provides 'backing_dev_info' in order to disable read-ahead. For 21988c2ecf20Sopenharmony_ci * UBIFS, I/O is not deferred, it is done immediately in readpage, 21998c2ecf20Sopenharmony_ci * which means the user would have to wait not just for their own I/O 22008c2ecf20Sopenharmony_ci * but the read-ahead I/O as well i.e. completely pointless. 22018c2ecf20Sopenharmony_ci * 22028c2ecf20Sopenharmony_ci * Read-ahead will be disabled because @sb->s_bdi->ra_pages is 0. Also 22038c2ecf20Sopenharmony_ci * @sb->s_bdi->capabilities are initialized to 0 so there won't be any 22048c2ecf20Sopenharmony_ci * writeback happening. 22058c2ecf20Sopenharmony_ci */ 22068c2ecf20Sopenharmony_ci err = super_setup_bdi_name(sb, "ubifs_%d_%d", c->vi.ubi_num, 22078c2ecf20Sopenharmony_ci c->vi.vol_id); 22088c2ecf20Sopenharmony_ci if (err) 22098c2ecf20Sopenharmony_ci goto out_close; 22108c2ecf20Sopenharmony_ci sb->s_bdi->ra_pages = 0; 22118c2ecf20Sopenharmony_ci sb->s_bdi->io_pages = 0; 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci sb->s_fs_info = c; 22148c2ecf20Sopenharmony_ci sb->s_magic = UBIFS_SUPER_MAGIC; 22158c2ecf20Sopenharmony_ci sb->s_blocksize = UBIFS_BLOCK_SIZE; 22168c2ecf20Sopenharmony_ci sb->s_blocksize_bits = UBIFS_BLOCK_SHIFT; 22178c2ecf20Sopenharmony_ci sb->s_maxbytes = c->max_inode_sz = key_max_inode_size(c); 22188c2ecf20Sopenharmony_ci if (c->max_inode_sz > MAX_LFS_FILESIZE) 22198c2ecf20Sopenharmony_ci sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE; 22208c2ecf20Sopenharmony_ci sb->s_op = &ubifs_super_operations; 22218c2ecf20Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_XATTR 22228c2ecf20Sopenharmony_ci sb->s_xattr = ubifs_xattr_handlers; 22238c2ecf20Sopenharmony_ci#endif 22248c2ecf20Sopenharmony_ci fscrypt_set_ops(sb, &ubifs_crypt_operations); 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci mutex_lock(&c->umount_mutex); 22278c2ecf20Sopenharmony_ci err = mount_ubifs(c); 22288c2ecf20Sopenharmony_ci if (err) { 22298c2ecf20Sopenharmony_ci ubifs_assert(c, err < 0); 22308c2ecf20Sopenharmony_ci goto out_unlock; 22318c2ecf20Sopenharmony_ci } 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci /* Read the root inode */ 22348c2ecf20Sopenharmony_ci root = ubifs_iget(sb, UBIFS_ROOT_INO); 22358c2ecf20Sopenharmony_ci if (IS_ERR(root)) { 22368c2ecf20Sopenharmony_ci err = PTR_ERR(root); 22378c2ecf20Sopenharmony_ci goto out_umount; 22388c2ecf20Sopenharmony_ci } 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci sb->s_root = d_make_root(root); 22418c2ecf20Sopenharmony_ci if (!sb->s_root) { 22428c2ecf20Sopenharmony_ci err = -ENOMEM; 22438c2ecf20Sopenharmony_ci goto out_umount; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci mutex_unlock(&c->umount_mutex); 22478c2ecf20Sopenharmony_ci return 0; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ciout_umount: 22508c2ecf20Sopenharmony_ci ubifs_umount(c); 22518c2ecf20Sopenharmony_ciout_unlock: 22528c2ecf20Sopenharmony_ci mutex_unlock(&c->umount_mutex); 22538c2ecf20Sopenharmony_ciout_close: 22548c2ecf20Sopenharmony_ci ubifs_release_options(c); 22558c2ecf20Sopenharmony_ci ubi_close_volume(c->ubi); 22568c2ecf20Sopenharmony_ciout: 22578c2ecf20Sopenharmony_ci return err; 22588c2ecf20Sopenharmony_ci} 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_cistatic int sb_test(struct super_block *sb, void *data) 22618c2ecf20Sopenharmony_ci{ 22628c2ecf20Sopenharmony_ci struct ubifs_info *c1 = data; 22638c2ecf20Sopenharmony_ci struct ubifs_info *c = sb->s_fs_info; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci return c->vi.cdev == c1->vi.cdev; 22668c2ecf20Sopenharmony_ci} 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_cistatic int sb_set(struct super_block *sb, void *data) 22698c2ecf20Sopenharmony_ci{ 22708c2ecf20Sopenharmony_ci sb->s_fs_info = data; 22718c2ecf20Sopenharmony_ci return set_anon_super(sb, NULL); 22728c2ecf20Sopenharmony_ci} 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_cistatic struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, 22758c2ecf20Sopenharmony_ci const char *name, void *data) 22768c2ecf20Sopenharmony_ci{ 22778c2ecf20Sopenharmony_ci struct ubi_volume_desc *ubi; 22788c2ecf20Sopenharmony_ci struct ubifs_info *c; 22798c2ecf20Sopenharmony_ci struct super_block *sb; 22808c2ecf20Sopenharmony_ci int err; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci dbg_gen("name %s, flags %#x", name, flags); 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_ci /* 22858c2ecf20Sopenharmony_ci * Get UBI device number and volume ID. Mount it read-only so far 22868c2ecf20Sopenharmony_ci * because this might be a new mount point, and UBI allows only one 22878c2ecf20Sopenharmony_ci * read-write user at a time. 22888c2ecf20Sopenharmony_ci */ 22898c2ecf20Sopenharmony_ci ubi = open_ubi(name, UBI_READONLY); 22908c2ecf20Sopenharmony_ci if (IS_ERR(ubi)) { 22918c2ecf20Sopenharmony_ci if (!(flags & SB_SILENT)) 22928c2ecf20Sopenharmony_ci pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d", 22938c2ecf20Sopenharmony_ci current->pid, name, (int)PTR_ERR(ubi)); 22948c2ecf20Sopenharmony_ci return ERR_CAST(ubi); 22958c2ecf20Sopenharmony_ci } 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci c = alloc_ubifs_info(ubi); 22988c2ecf20Sopenharmony_ci if (!c) { 22998c2ecf20Sopenharmony_ci err = -ENOMEM; 23008c2ecf20Sopenharmony_ci goto out_close; 23018c2ecf20Sopenharmony_ci } 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci sb = sget(fs_type, sb_test, sb_set, flags, c); 23068c2ecf20Sopenharmony_ci if (IS_ERR(sb)) { 23078c2ecf20Sopenharmony_ci err = PTR_ERR(sb); 23088c2ecf20Sopenharmony_ci kfree(c); 23098c2ecf20Sopenharmony_ci goto out_close; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci if (sb->s_root) { 23138c2ecf20Sopenharmony_ci struct ubifs_info *c1 = sb->s_fs_info; 23148c2ecf20Sopenharmony_ci kfree(c); 23158c2ecf20Sopenharmony_ci /* A new mount point for already mounted UBIFS */ 23168c2ecf20Sopenharmony_ci dbg_gen("this ubi volume is already mounted"); 23178c2ecf20Sopenharmony_ci if (!!(flags & SB_RDONLY) != c1->ro_mount) { 23188c2ecf20Sopenharmony_ci err = -EBUSY; 23198c2ecf20Sopenharmony_ci goto out_deact; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci } else { 23228c2ecf20Sopenharmony_ci err = ubifs_fill_super(sb, data, flags & SB_SILENT ? 1 : 0); 23238c2ecf20Sopenharmony_ci if (err) 23248c2ecf20Sopenharmony_ci goto out_deact; 23258c2ecf20Sopenharmony_ci /* We do not support atime */ 23268c2ecf20Sopenharmony_ci sb->s_flags |= SB_ACTIVE; 23278c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_UBIFS_ATIME_SUPPORT)) 23288c2ecf20Sopenharmony_ci ubifs_msg(c, "full atime support is enabled."); 23298c2ecf20Sopenharmony_ci else 23308c2ecf20Sopenharmony_ci sb->s_flags |= SB_NOATIME; 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci /* 'fill_super()' opens ubi again so we must close it here */ 23348c2ecf20Sopenharmony_ci ubi_close_volume(ubi); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci return dget(sb->s_root); 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ciout_deact: 23398c2ecf20Sopenharmony_ci deactivate_locked_super(sb); 23408c2ecf20Sopenharmony_ciout_close: 23418c2ecf20Sopenharmony_ci ubi_close_volume(ubi); 23428c2ecf20Sopenharmony_ci return ERR_PTR(err); 23438c2ecf20Sopenharmony_ci} 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_cistatic void kill_ubifs_super(struct super_block *s) 23468c2ecf20Sopenharmony_ci{ 23478c2ecf20Sopenharmony_ci struct ubifs_info *c = s->s_fs_info; 23488c2ecf20Sopenharmony_ci kill_anon_super(s); 23498c2ecf20Sopenharmony_ci kfree(c); 23508c2ecf20Sopenharmony_ci} 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_cistatic struct file_system_type ubifs_fs_type = { 23538c2ecf20Sopenharmony_ci .name = "ubifs", 23548c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 23558c2ecf20Sopenharmony_ci .mount = ubifs_mount, 23568c2ecf20Sopenharmony_ci .kill_sb = kill_ubifs_super, 23578c2ecf20Sopenharmony_ci}; 23588c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("ubifs"); 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci/* 23618c2ecf20Sopenharmony_ci * Inode slab cache constructor. 23628c2ecf20Sopenharmony_ci */ 23638c2ecf20Sopenharmony_cistatic void inode_slab_ctor(void *obj) 23648c2ecf20Sopenharmony_ci{ 23658c2ecf20Sopenharmony_ci struct ubifs_inode *ui = obj; 23668c2ecf20Sopenharmony_ci inode_init_once(&ui->vfs_inode); 23678c2ecf20Sopenharmony_ci} 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_cistatic int __init ubifs_init(void) 23708c2ecf20Sopenharmony_ci{ 23718c2ecf20Sopenharmony_ci int err; 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct ubifs_ch) != 24); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci /* Make sure node sizes are 8-byte aligned */ 23768c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_CH_SZ & 7); 23778c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_INO_NODE_SZ & 7); 23788c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_DENT_NODE_SZ & 7); 23798c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_XENT_NODE_SZ & 7); 23808c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_DATA_NODE_SZ & 7); 23818c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ & 7); 23828c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_SB_NODE_SZ & 7); 23838c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MST_NODE_SZ & 7); 23848c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_REF_NODE_SZ & 7); 23858c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_CS_NODE_SZ & 7); 23868c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_ORPH_NODE_SZ & 7); 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ & 7); 23898c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ & 7); 23908c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ & 7); 23918c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ & 7); 23928c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_NODE_SZ & 7); 23938c2ecf20Sopenharmony_ci BUILD_BUG_ON(MIN_WRITE_SZ & 7); 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_ci /* Check min. node size */ 23968c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_INO_NODE_SZ < MIN_WRITE_SZ); 23978c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_DENT_NODE_SZ < MIN_WRITE_SZ); 23988c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_XENT_NODE_SZ < MIN_WRITE_SZ); 23998c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_TRUN_NODE_SZ < MIN_WRITE_SZ); 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_DENT_NODE_SZ > UBIFS_MAX_NODE_SZ); 24028c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_XENT_NODE_SZ > UBIFS_MAX_NODE_SZ); 24038c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_DATA_NODE_SZ > UBIFS_MAX_NODE_SZ); 24048c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MAX_INO_NODE_SZ > UBIFS_MAX_NODE_SZ); 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci /* Defined node sizes */ 24078c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_SB_NODE_SZ != 4096); 24088c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_MST_NODE_SZ != 512); 24098c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_INO_NODE_SZ != 160); 24108c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_REF_NODE_SZ != 64); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci /* 24138c2ecf20Sopenharmony_ci * We use 2 bit wide bit-fields to store compression type, which should 24148c2ecf20Sopenharmony_ci * be amended if more compressors are added. The bit-fields are: 24158c2ecf20Sopenharmony_ci * @compr_type in 'struct ubifs_inode', @default_compr in 24168c2ecf20Sopenharmony_ci * 'struct ubifs_info' and @compr_type in 'struct ubifs_mount_opts'. 24178c2ecf20Sopenharmony_ci */ 24188c2ecf20Sopenharmony_ci BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4); 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci /* 24218c2ecf20Sopenharmony_ci * We require that PAGE_SIZE is greater-than-or-equal-to 24228c2ecf20Sopenharmony_ci * UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2. 24238c2ecf20Sopenharmony_ci */ 24248c2ecf20Sopenharmony_ci if (PAGE_SIZE < UBIFS_BLOCK_SIZE) { 24258c2ecf20Sopenharmony_ci pr_err("UBIFS error (pid %d): VFS page cache size is %u bytes, but UBIFS requires at least 4096 bytes", 24268c2ecf20Sopenharmony_ci current->pid, (unsigned int)PAGE_SIZE); 24278c2ecf20Sopenharmony_ci return -EINVAL; 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci ubifs_inode_slab = kmem_cache_create("ubifs_inode_slab", 24318c2ecf20Sopenharmony_ci sizeof(struct ubifs_inode), 0, 24328c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD | SLAB_RECLAIM_ACCOUNT | 24338c2ecf20Sopenharmony_ci SLAB_ACCOUNT, &inode_slab_ctor); 24348c2ecf20Sopenharmony_ci if (!ubifs_inode_slab) 24358c2ecf20Sopenharmony_ci return -ENOMEM; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci err = register_shrinker(&ubifs_shrinker_info); 24388c2ecf20Sopenharmony_ci if (err) 24398c2ecf20Sopenharmony_ci goto out_slab; 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci err = ubifs_compressors_init(); 24428c2ecf20Sopenharmony_ci if (err) 24438c2ecf20Sopenharmony_ci goto out_shrinker; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci dbg_debugfs_init(); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci err = register_filesystem(&ubifs_fs_type); 24488c2ecf20Sopenharmony_ci if (err) { 24498c2ecf20Sopenharmony_ci pr_err("UBIFS error (pid %d): cannot register file system, error %d", 24508c2ecf20Sopenharmony_ci current->pid, err); 24518c2ecf20Sopenharmony_ci goto out_dbg; 24528c2ecf20Sopenharmony_ci } 24538c2ecf20Sopenharmony_ci return 0; 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_ciout_dbg: 24568c2ecf20Sopenharmony_ci dbg_debugfs_exit(); 24578c2ecf20Sopenharmony_ci ubifs_compressors_exit(); 24588c2ecf20Sopenharmony_ciout_shrinker: 24598c2ecf20Sopenharmony_ci unregister_shrinker(&ubifs_shrinker_info); 24608c2ecf20Sopenharmony_ciout_slab: 24618c2ecf20Sopenharmony_ci kmem_cache_destroy(ubifs_inode_slab); 24628c2ecf20Sopenharmony_ci return err; 24638c2ecf20Sopenharmony_ci} 24648c2ecf20Sopenharmony_ci/* late_initcall to let compressors initialize first */ 24658c2ecf20Sopenharmony_cilate_initcall(ubifs_init); 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_cistatic void __exit ubifs_exit(void) 24688c2ecf20Sopenharmony_ci{ 24698c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&ubifs_infos)); 24708c2ecf20Sopenharmony_ci WARN_ON(atomic_long_read(&ubifs_clean_zn_cnt) != 0); 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci dbg_debugfs_exit(); 24738c2ecf20Sopenharmony_ci ubifs_compressors_exit(); 24748c2ecf20Sopenharmony_ci unregister_shrinker(&ubifs_shrinker_info); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci /* 24778c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 24788c2ecf20Sopenharmony_ci * destroy cache. 24798c2ecf20Sopenharmony_ci */ 24808c2ecf20Sopenharmony_ci rcu_barrier(); 24818c2ecf20Sopenharmony_ci kmem_cache_destroy(ubifs_inode_slab); 24828c2ecf20Sopenharmony_ci unregister_filesystem(&ubifs_fs_type); 24838c2ecf20Sopenharmony_ci} 24848c2ecf20Sopenharmony_cimodule_exit(ubifs_exit); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 24878c2ecf20Sopenharmony_ciMODULE_VERSION(__stringify(UBIFS_VERSION)); 24888c2ecf20Sopenharmony_ciMODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); 24898c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("UBIFS - UBI File System"); 2490