18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* * This file is part of UBIFS. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 58c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2007 University of Szeged, Hungary 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём) 88c2ecf20Sopenharmony_ci * Adrian Hunter 98c2ecf20Sopenharmony_ci * Zoltan Sogor 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* 138c2ecf20Sopenharmony_ci * This file implements directory operations. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * All FS operations in this file allocate budget before writing anything to the 168c2ecf20Sopenharmony_ci * media. If they fail to allocate it, the error is returned. The only 178c2ecf20Sopenharmony_ci * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even 188c2ecf20Sopenharmony_ci * if they unable to allocate the budget, because deletion %-ENOSPC failure is 198c2ecf20Sopenharmony_ci * not what users are usually ready to get. UBIFS budgeting subsystem has some 208c2ecf20Sopenharmony_ci * space reserved for these purposes. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * All operations in this file write all inodes which they change straight 238c2ecf20Sopenharmony_ci * away, instead of marking them dirty. For example, 'ubifs_link()' changes 248c2ecf20Sopenharmony_ci * @i_size of the parent inode and writes the parent inode together with the 258c2ecf20Sopenharmony_ci * target inode. This was done to simplify file-system recovery which would 268c2ecf20Sopenharmony_ci * otherwise be very difficult to do. The only exception is rename which marks 278c2ecf20Sopenharmony_ci * the re-named inode dirty (because its @i_ctime is updated) but does not 288c2ecf20Sopenharmony_ci * write it, but just marks it as dirty. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "ubifs.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/** 348c2ecf20Sopenharmony_ci * inherit_flags - inherit flags of the parent inode. 358c2ecf20Sopenharmony_ci * @dir: parent inode 368c2ecf20Sopenharmony_ci * @mode: new inode mode flags 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * This is a helper function for 'ubifs_new_inode()' which inherits flag of the 398c2ecf20Sopenharmony_ci * parent directory inode @dir. UBIFS inodes inherit the following flags: 408c2ecf20Sopenharmony_ci * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on 418c2ecf20Sopenharmony_ci * sub-directory basis; 428c2ecf20Sopenharmony_ci * o %UBIFS_SYNC_FL - useful for the same reasons; 438c2ecf20Sopenharmony_ci * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * This function returns the inherited flags. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_cistatic int inherit_flags(const struct inode *dir, umode_t mode) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci int flags; 508c2ecf20Sopenharmony_ci const struct ubifs_inode *ui = ubifs_inode(dir); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!S_ISDIR(dir->i_mode)) 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * The parent is not a directory, which means that an extended 558c2ecf20Sopenharmony_ci * attribute inode is being created. No flags. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); 608c2ecf20Sopenharmony_ci if (!S_ISDIR(mode)) 618c2ecf20Sopenharmony_ci /* The "DIRSYNC" flag only applies to directories */ 628c2ecf20Sopenharmony_ci flags &= ~UBIFS_DIRSYNC_FL; 638c2ecf20Sopenharmony_ci return flags; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * ubifs_new_inode - allocate new UBIFS inode object. 688c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 698c2ecf20Sopenharmony_ci * @dir: parent directory inode 708c2ecf20Sopenharmony_ci * @mode: inode mode flags 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * This function finds an unused inode number, allocates new inode and 738c2ecf20Sopenharmony_ci * initializes it. Returns new inode in case of success and an error code in 748c2ecf20Sopenharmony_ci * case of failure. 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistruct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, 778c2ecf20Sopenharmony_ci umode_t mode) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci int err; 808c2ecf20Sopenharmony_ci struct inode *inode; 818c2ecf20Sopenharmony_ci struct ubifs_inode *ui; 828c2ecf20Sopenharmony_ci bool encrypted = false; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci inode = new_inode(c->vfs_sb); 858c2ecf20Sopenharmony_ci ui = ubifs_inode(inode); 868c2ecf20Sopenharmony_ci if (!inode) 878c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci /* 908c2ecf20Sopenharmony_ci * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and 918c2ecf20Sopenharmony_ci * marking them dirty in file write path (see 'file_update_time()'). 928c2ecf20Sopenharmony_ci * UBIFS has to fully control "clean <-> dirty" transitions of inodes 938c2ecf20Sopenharmony_ci * to make budgeting work. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci inode->i_flags |= S_NOCMTIME; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci inode_init_owner(inode, dir, mode); 988c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = 998c2ecf20Sopenharmony_ci current_time(inode); 1008c2ecf20Sopenharmony_ci inode->i_mapping->nrpages = 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci err = fscrypt_prepare_new_inode(dir, inode, &encrypted); 1038c2ecf20Sopenharmony_ci if (err) { 1048c2ecf20Sopenharmony_ci ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err); 1058c2ecf20Sopenharmony_ci goto out_iput; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci switch (mode & S_IFMT) { 1098c2ecf20Sopenharmony_ci case S_IFREG: 1108c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &ubifs_file_address_operations; 1118c2ecf20Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 1128c2ecf20Sopenharmony_ci inode->i_fop = &ubifs_file_operations; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci case S_IFDIR: 1158c2ecf20Sopenharmony_ci inode->i_op = &ubifs_dir_inode_operations; 1168c2ecf20Sopenharmony_ci inode->i_fop = &ubifs_dir_operations; 1178c2ecf20Sopenharmony_ci inode->i_size = ui->ui_size = UBIFS_INO_NODE_SZ; 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case S_IFLNK: 1208c2ecf20Sopenharmony_ci inode->i_op = &ubifs_symlink_inode_operations; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case S_IFSOCK: 1238c2ecf20Sopenharmony_ci case S_IFIFO: 1248c2ecf20Sopenharmony_ci case S_IFBLK: 1258c2ecf20Sopenharmony_ci case S_IFCHR: 1268c2ecf20Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci default: 1298c2ecf20Sopenharmony_ci BUG(); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci ui->flags = inherit_flags(dir, mode); 1338c2ecf20Sopenharmony_ci ubifs_set_inode_flags(inode); 1348c2ecf20Sopenharmony_ci if (S_ISREG(mode)) 1358c2ecf20Sopenharmony_ci ui->compr_type = c->default_compr; 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci ui->compr_type = UBIFS_COMPR_NONE; 1388c2ecf20Sopenharmony_ci ui->synced_i_size = 0; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci spin_lock(&c->cnt_lock); 1418c2ecf20Sopenharmony_ci /* Inode number overflow is currently not supported */ 1428c2ecf20Sopenharmony_ci if (c->highest_inum >= INUM_WARN_WATERMARK) { 1438c2ecf20Sopenharmony_ci if (c->highest_inum >= INUM_WATERMARK) { 1448c2ecf20Sopenharmony_ci spin_unlock(&c->cnt_lock); 1458c2ecf20Sopenharmony_ci ubifs_err(c, "out of inode numbers"); 1468c2ecf20Sopenharmony_ci err = -EINVAL; 1478c2ecf20Sopenharmony_ci goto out_iput; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci ubifs_warn(c, "running out of inode numbers (current %lu, max %u)", 1508c2ecf20Sopenharmony_ci (unsigned long)c->highest_inum, INUM_WATERMARK); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci inode->i_ino = ++c->highest_inum; 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * The creation sequence number remains with this inode for its 1568c2ecf20Sopenharmony_ci * lifetime. All nodes for this inode have a greater sequence number, 1578c2ecf20Sopenharmony_ci * and so it is possible to distinguish obsolete nodes belonging to a 1588c2ecf20Sopenharmony_ci * previous incarnation of the same inode number - for example, for the 1598c2ecf20Sopenharmony_ci * purpose of rebuilding the index. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci ui->creat_sqnum = ++c->max_sqnum; 1628c2ecf20Sopenharmony_ci spin_unlock(&c->cnt_lock); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (encrypted) { 1658c2ecf20Sopenharmony_ci err = fscrypt_set_context(inode, NULL); 1668c2ecf20Sopenharmony_ci if (err) { 1678c2ecf20Sopenharmony_ci ubifs_err(c, "fscrypt_set_context failed: %i", err); 1688c2ecf20Sopenharmony_ci goto out_iput; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return inode; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ciout_iput: 1758c2ecf20Sopenharmony_ci make_bad_inode(inode); 1768c2ecf20Sopenharmony_ci iput(inode); 1778c2ecf20Sopenharmony_ci return ERR_PTR(err); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int dbg_check_name(const struct ubifs_info *c, 1818c2ecf20Sopenharmony_ci const struct ubifs_dent_node *dent, 1828c2ecf20Sopenharmony_ci const struct fscrypt_name *nm) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci if (!dbg_is_chk_gen(c)) 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci if (le16_to_cpu(dent->nlen) != fname_len(nm)) 1878c2ecf20Sopenharmony_ci return -EINVAL; 1888c2ecf20Sopenharmony_ci if (memcmp(dent->name, fname_name(nm), fname_len(nm))) 1898c2ecf20Sopenharmony_ci return -EINVAL; 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, 1948c2ecf20Sopenharmony_ci unsigned int flags) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci int err; 1978c2ecf20Sopenharmony_ci union ubifs_key key; 1988c2ecf20Sopenharmony_ci struct inode *inode = NULL; 1998c2ecf20Sopenharmony_ci struct ubifs_dent_node *dent = NULL; 2008c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 2018c2ecf20Sopenharmony_ci struct fscrypt_name nm; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci err = fscrypt_prepare_lookup(dir, dentry, &nm); 2068c2ecf20Sopenharmony_ci if (err == -ENOENT) 2078c2ecf20Sopenharmony_ci return d_splice_alias(NULL, dentry); 2088c2ecf20Sopenharmony_ci if (err) 2098c2ecf20Sopenharmony_ci return ERR_PTR(err); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (fname_len(&nm) > UBIFS_MAX_NLEN) { 2128c2ecf20Sopenharmony_ci inode = ERR_PTR(-ENAMETOOLONG); 2138c2ecf20Sopenharmony_ci goto done; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); 2178c2ecf20Sopenharmony_ci if (!dent) { 2188c2ecf20Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 2198c2ecf20Sopenharmony_ci goto done; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (fname_name(&nm) == NULL) { 2238c2ecf20Sopenharmony_ci if (nm.hash & ~UBIFS_S_KEY_HASH_MASK) 2248c2ecf20Sopenharmony_ci goto done; /* ENOENT */ 2258c2ecf20Sopenharmony_ci dent_key_init_hash(c, &key, dir->i_ino, nm.hash); 2268c2ecf20Sopenharmony_ci err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash); 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_ci dent_key_init(c, &key, dir->i_ino, &nm); 2298c2ecf20Sopenharmony_ci err = ubifs_tnc_lookup_nm(c, &key, dent, &nm); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (err) { 2338c2ecf20Sopenharmony_ci if (err == -ENOENT) 2348c2ecf20Sopenharmony_ci dbg_gen("not found"); 2358c2ecf20Sopenharmony_ci else 2368c2ecf20Sopenharmony_ci inode = ERR_PTR(err); 2378c2ecf20Sopenharmony_ci goto done; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (dbg_check_name(c, dent, &nm)) { 2418c2ecf20Sopenharmony_ci inode = ERR_PTR(-EINVAL); 2428c2ecf20Sopenharmony_ci goto done; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); 2468c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * This should not happen. Probably the file-system needs 2498c2ecf20Sopenharmony_ci * checking. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 2528c2ecf20Sopenharmony_ci ubifs_err(c, "dead directory entry '%pd', error %d", 2538c2ecf20Sopenharmony_ci dentry, err); 2548c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 2558c2ecf20Sopenharmony_ci goto done; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(dir) && 2598c2ecf20Sopenharmony_ci (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && 2608c2ecf20Sopenharmony_ci !fscrypt_has_permitted_context(dir, inode)) { 2618c2ecf20Sopenharmony_ci ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu", 2628c2ecf20Sopenharmony_ci dir->i_ino, inode->i_ino); 2638c2ecf20Sopenharmony_ci iput(inode); 2648c2ecf20Sopenharmony_ci inode = ERR_PTR(-EPERM); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cidone: 2688c2ecf20Sopenharmony_ci kfree(dent); 2698c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 2708c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int ubifs_prepare_create(struct inode *dir, struct dentry *dentry, 2748c2ecf20Sopenharmony_ci struct fscrypt_name *nm) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci if (fscrypt_is_nokey_name(dentry)) 2778c2ecf20Sopenharmony_ci return -ENOKEY; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return fscrypt_setup_filename(dir, &dentry->d_name, 0, nm); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode, 2838c2ecf20Sopenharmony_ci bool excl) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct inode *inode; 2868c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 2878c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 2888c2ecf20Sopenharmony_ci .dirtied_ino = 1 }; 2898c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 2908c2ecf20Sopenharmony_ci struct fscrypt_name nm; 2918c2ecf20Sopenharmony_ci int err, sz_change; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* 2948c2ecf20Sopenharmony_ci * Budget request settings: new inode, new direntry, changing the 2958c2ecf20Sopenharmony_ci * parent directory inode. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 2998c2ecf20Sopenharmony_ci dentry, mode, dir->i_ino); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 3028c2ecf20Sopenharmony_ci if (err) 3038c2ecf20Sopenharmony_ci return err; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 3068c2ecf20Sopenharmony_ci if (err) 3078c2ecf20Sopenharmony_ci goto out_budg; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode); 3128c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 3138c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 3148c2ecf20Sopenharmony_ci goto out_fname; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 3188c2ecf20Sopenharmony_ci if (err) 3198c2ecf20Sopenharmony_ci goto out_inode; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 3228c2ecf20Sopenharmony_ci dir->i_size += sz_change; 3238c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 3248c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 3258c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 3268c2ecf20Sopenharmony_ci if (err) 3278c2ecf20Sopenharmony_ci goto out_cancel; 3288c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 3318c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 3328c2ecf20Sopenharmony_ci insert_inode_hash(inode); 3338c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ciout_cancel: 3378c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 3388c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 3398c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 3408c2ecf20Sopenharmony_ciout_inode: 3418c2ecf20Sopenharmony_ci make_bad_inode(inode); 3428c2ecf20Sopenharmony_ci iput(inode); 3438c2ecf20Sopenharmony_ciout_fname: 3448c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 3458c2ecf20Sopenharmony_ciout_budg: 3468c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 3478c2ecf20Sopenharmony_ci ubifs_err(c, "cannot create regular file, error %d", err); 3488c2ecf20Sopenharmony_ci return err; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic struct inode *create_whiteout(struct inode *dir, struct dentry *dentry) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci int err; 3548c2ecf20Sopenharmony_ci umode_t mode = S_IFCHR | WHITEOUT_MODE; 3558c2ecf20Sopenharmony_ci struct inode *inode; 3568c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 3578c2ecf20Sopenharmony_ci struct fscrypt_name nm; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* 3608c2ecf20Sopenharmony_ci * Create an inode('nlink = 1') for whiteout without updating journal, 3618c2ecf20Sopenharmony_ci * let ubifs_jnl_rename() store it on flash to complete rename whiteout 3628c2ecf20Sopenharmony_ci * atomically. 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 3668c2ecf20Sopenharmony_ci dentry, mode, dir->i_ino); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); 3698c2ecf20Sopenharmony_ci if (err) 3708c2ecf20Sopenharmony_ci return ERR_PTR(err); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode); 3738c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 3748c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 3758c2ecf20Sopenharmony_ci goto out_free; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, WHITEOUT_DEV); 3798c2ecf20Sopenharmony_ci ubifs_assert(c, inode->i_op == &ubifs_file_inode_operations); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 3828c2ecf20Sopenharmony_ci if (err) 3838c2ecf20Sopenharmony_ci goto out_inode; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* The dir size is updated by do_rename. */ 3868c2ecf20Sopenharmony_ci insert_inode_hash(inode); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return inode; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciout_inode: 3918c2ecf20Sopenharmony_ci make_bad_inode(inode); 3928c2ecf20Sopenharmony_ci iput(inode); 3938c2ecf20Sopenharmony_ciout_free: 3948c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 3958c2ecf20Sopenharmony_ci ubifs_err(c, "cannot create whiteout file, error %d", err); 3968c2ecf20Sopenharmony_ci return ERR_PTR(err); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci/** 4008c2ecf20Sopenharmony_ci * lock_2_inodes - a wrapper for locking two UBIFS inodes. 4018c2ecf20Sopenharmony_ci * @inode1: first inode 4028c2ecf20Sopenharmony_ci * @inode2: second inode 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci * We do not implement any tricks to guarantee strict lock ordering, because 4058c2ecf20Sopenharmony_ci * VFS has already done it for us on the @i_mutex. So this is just a simple 4068c2ecf20Sopenharmony_ci * wrapper function. 4078c2ecf20Sopenharmony_ci */ 4088c2ecf20Sopenharmony_cistatic void lock_2_inodes(struct inode *inode1, struct inode *inode2) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); 4118c2ecf20Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/** 4158c2ecf20Sopenharmony_ci * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. 4168c2ecf20Sopenharmony_ci * @inode1: first inode 4178c2ecf20Sopenharmony_ci * @inode2: second inode 4188c2ecf20Sopenharmony_ci */ 4198c2ecf20Sopenharmony_cistatic void unlock_2_inodes(struct inode *inode1, struct inode *inode2) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci mutex_unlock(&ubifs_inode(inode2)->ui_mutex); 4228c2ecf20Sopenharmony_ci mutex_unlock(&ubifs_inode(inode1)->ui_mutex); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int ubifs_tmpfile(struct inode *dir, struct dentry *dentry, 4268c2ecf20Sopenharmony_ci umode_t mode) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct inode *inode; 4298c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 4308c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 4318c2ecf20Sopenharmony_ci .dirtied_ino = 1}; 4328c2ecf20Sopenharmony_ci struct ubifs_budget_req ino_req = { .dirtied_ino = 1 }; 4338c2ecf20Sopenharmony_ci struct ubifs_inode *ui; 4348c2ecf20Sopenharmony_ci int err, instantiated = 0; 4358c2ecf20Sopenharmony_ci struct fscrypt_name nm; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* 4388c2ecf20Sopenharmony_ci * Budget request settings: new inode, new direntry, changing the 4398c2ecf20Sopenharmony_ci * parent directory inode. 4408c2ecf20Sopenharmony_ci * Allocate budget separately for new dirtied inode, the budget will 4418c2ecf20Sopenharmony_ci * be released via writeback. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 4458c2ecf20Sopenharmony_ci dentry, mode, dir->i_ino); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); 4488c2ecf20Sopenharmony_ci if (err) 4498c2ecf20Sopenharmony_ci return err; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 4528c2ecf20Sopenharmony_ci if (err) { 4538c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 4548c2ecf20Sopenharmony_ci return err; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &ino_req); 4588c2ecf20Sopenharmony_ci if (err) { 4598c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 4608c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 4618c2ecf20Sopenharmony_ci return err; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode); 4658c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 4668c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 4678c2ecf20Sopenharmony_ci goto out_budg; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci ui = ubifs_inode(inode); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 4728c2ecf20Sopenharmony_ci if (err) 4738c2ecf20Sopenharmony_ci goto out_inode; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 4768c2ecf20Sopenharmony_ci insert_inode_hash(inode); 4778c2ecf20Sopenharmony_ci d_tmpfile(dentry, inode); 4788c2ecf20Sopenharmony_ci ubifs_assert(c, ui->dirty); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci instantiated = 1; 4818c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci lock_2_inodes(dir, inode); 4848c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); 4858c2ecf20Sopenharmony_ci if (err) 4868c2ecf20Sopenharmony_ci goto out_cancel; 4878c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 4908c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ciout_cancel: 4958c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 4968c2ecf20Sopenharmony_ciout_inode: 4978c2ecf20Sopenharmony_ci make_bad_inode(inode); 4988c2ecf20Sopenharmony_ci if (!instantiated) 4998c2ecf20Sopenharmony_ci iput(inode); 5008c2ecf20Sopenharmony_ciout_budg: 5018c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 5028c2ecf20Sopenharmony_ci if (!instantiated) 5038c2ecf20Sopenharmony_ci ubifs_release_budget(c, &ino_req); 5048c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 5058c2ecf20Sopenharmony_ci ubifs_err(c, "cannot create temporary file, error %d", err); 5068c2ecf20Sopenharmony_ci return err; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci/** 5108c2ecf20Sopenharmony_ci * vfs_dent_type - get VFS directory entry type. 5118c2ecf20Sopenharmony_ci * @type: UBIFS directory entry type 5128c2ecf20Sopenharmony_ci * 5138c2ecf20Sopenharmony_ci * This function converts UBIFS directory entry type into VFS directory entry 5148c2ecf20Sopenharmony_ci * type. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_cistatic unsigned int vfs_dent_type(uint8_t type) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci switch (type) { 5198c2ecf20Sopenharmony_ci case UBIFS_ITYPE_REG: 5208c2ecf20Sopenharmony_ci return DT_REG; 5218c2ecf20Sopenharmony_ci case UBIFS_ITYPE_DIR: 5228c2ecf20Sopenharmony_ci return DT_DIR; 5238c2ecf20Sopenharmony_ci case UBIFS_ITYPE_LNK: 5248c2ecf20Sopenharmony_ci return DT_LNK; 5258c2ecf20Sopenharmony_ci case UBIFS_ITYPE_BLK: 5268c2ecf20Sopenharmony_ci return DT_BLK; 5278c2ecf20Sopenharmony_ci case UBIFS_ITYPE_CHR: 5288c2ecf20Sopenharmony_ci return DT_CHR; 5298c2ecf20Sopenharmony_ci case UBIFS_ITYPE_FIFO: 5308c2ecf20Sopenharmony_ci return DT_FIFO; 5318c2ecf20Sopenharmony_ci case UBIFS_ITYPE_SOCK: 5328c2ecf20Sopenharmony_ci return DT_SOCK; 5338c2ecf20Sopenharmony_ci default: 5348c2ecf20Sopenharmony_ci BUG(); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci} 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci/* 5408c2ecf20Sopenharmony_ci * The classical Unix view for directory is that it is a linear array of 5418c2ecf20Sopenharmony_ci * (name, inode number) entries. Linux/VFS assumes this model as well. 5428c2ecf20Sopenharmony_ci * Particularly, 'readdir()' call wants us to return a directory entry offset 5438c2ecf20Sopenharmony_ci * which later may be used to continue 'readdir()'ing the directory or to 5448c2ecf20Sopenharmony_ci * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this 5458c2ecf20Sopenharmony_ci * model because directory entries are identified by keys, which may collide. 5468c2ecf20Sopenharmony_ci * 5478c2ecf20Sopenharmony_ci * UBIFS uses directory entry hash value for directory offsets, so 5488c2ecf20Sopenharmony_ci * 'seekdir()'/'telldir()' may not always work because of possible key 5498c2ecf20Sopenharmony_ci * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work 5508c2ecf20Sopenharmony_ci * properly by means of saving full directory entry name in the private field 5518c2ecf20Sopenharmony_ci * of the file description object. 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * This means that UBIFS cannot support NFS which requires full 5548c2ecf20Sopenharmony_ci * 'seekdir()'/'telldir()' support. 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_cistatic int ubifs_readdir(struct file *file, struct dir_context *ctx) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci int fstr_real_len = 0, err = 0; 5598c2ecf20Sopenharmony_ci struct fscrypt_name nm; 5608c2ecf20Sopenharmony_ci struct fscrypt_str fstr = {0}; 5618c2ecf20Sopenharmony_ci union ubifs_key key; 5628c2ecf20Sopenharmony_ci struct ubifs_dent_node *dent; 5638c2ecf20Sopenharmony_ci struct inode *dir = file_inode(file); 5648c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 5658c2ecf20Sopenharmony_ci bool encrypted = IS_ENCRYPTED(dir); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2) 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * The directory was seek'ed to a senseless position or there 5728c2ecf20Sopenharmony_ci * are no more entries. 5738c2ecf20Sopenharmony_ci */ 5748c2ecf20Sopenharmony_ci return 0; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (encrypted) { 5778c2ecf20Sopenharmony_ci err = fscrypt_get_encryption_info(dir); 5788c2ecf20Sopenharmony_ci if (err) 5798c2ecf20Sopenharmony_ci return err; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci err = fscrypt_fname_alloc_buffer(UBIFS_MAX_NLEN, &fstr); 5828c2ecf20Sopenharmony_ci if (err) 5838c2ecf20Sopenharmony_ci return err; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci fstr_real_len = fstr.len; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci if (file->f_version == 0) { 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * The file was seek'ed, which means that @file->private_data 5918c2ecf20Sopenharmony_ci * is now invalid. This may also be just the first 5928c2ecf20Sopenharmony_ci * 'ubifs_readdir()' invocation, in which case 5938c2ecf20Sopenharmony_ci * @file->private_data is NULL, and the below code is 5948c2ecf20Sopenharmony_ci * basically a no-op. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci kfree(file->private_data); 5978c2ecf20Sopenharmony_ci file->private_data = NULL; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* 6018c2ecf20Sopenharmony_ci * 'generic_file_llseek()' unconditionally sets @file->f_version to 6028c2ecf20Sopenharmony_ci * zero, and we use this for detecting whether the file was seek'ed. 6038c2ecf20Sopenharmony_ci */ 6048c2ecf20Sopenharmony_ci file->f_version = 1; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* File positions 0 and 1 correspond to "." and ".." */ 6078c2ecf20Sopenharmony_ci if (ctx->pos < 2) { 6088c2ecf20Sopenharmony_ci ubifs_assert(c, !file->private_data); 6098c2ecf20Sopenharmony_ci if (!dir_emit_dots(file, ctx)) { 6108c2ecf20Sopenharmony_ci if (encrypted) 6118c2ecf20Sopenharmony_ci fscrypt_fname_free_buffer(&fstr); 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* Find the first entry in TNC and save it */ 6168c2ecf20Sopenharmony_ci lowest_dent_key(c, &key, dir->i_ino); 6178c2ecf20Sopenharmony_ci fname_len(&nm) = 0; 6188c2ecf20Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 6198c2ecf20Sopenharmony_ci if (IS_ERR(dent)) { 6208c2ecf20Sopenharmony_ci err = PTR_ERR(dent); 6218c2ecf20Sopenharmony_ci goto out; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci ctx->pos = key_hash_flash(c, &dent->key); 6258c2ecf20Sopenharmony_ci file->private_data = dent; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci dent = file->private_data; 6298c2ecf20Sopenharmony_ci if (!dent) { 6308c2ecf20Sopenharmony_ci /* 6318c2ecf20Sopenharmony_ci * The directory was seek'ed to and is now readdir'ed. 6328c2ecf20Sopenharmony_ci * Find the entry corresponding to @ctx->pos or the closest one. 6338c2ecf20Sopenharmony_ci */ 6348c2ecf20Sopenharmony_ci dent_key_init_hash(c, &key, dir->i_ino, ctx->pos); 6358c2ecf20Sopenharmony_ci fname_len(&nm) = 0; 6368c2ecf20Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 6378c2ecf20Sopenharmony_ci if (IS_ERR(dent)) { 6388c2ecf20Sopenharmony_ci err = PTR_ERR(dent); 6398c2ecf20Sopenharmony_ci goto out; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci ctx->pos = key_hash_flash(c, &dent->key); 6428c2ecf20Sopenharmony_ci file->private_data = dent; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci while (1) { 6468c2ecf20Sopenharmony_ci dbg_gen("ino %llu, new f_pos %#x", 6478c2ecf20Sopenharmony_ci (unsigned long long)le64_to_cpu(dent->inum), 6488c2ecf20Sopenharmony_ci key_hash_flash(c, &dent->key)); 6498c2ecf20Sopenharmony_ci ubifs_assert(c, le64_to_cpu(dent->ch.sqnum) > 6508c2ecf20Sopenharmony_ci ubifs_inode(dir)->creat_sqnum); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci fname_len(&nm) = le16_to_cpu(dent->nlen); 6538c2ecf20Sopenharmony_ci fname_name(&nm) = dent->name; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci if (encrypted) { 6568c2ecf20Sopenharmony_ci fstr.len = fstr_real_len; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, 6598c2ecf20Sopenharmony_ci &dent->key), 6608c2ecf20Sopenharmony_ci le32_to_cpu(dent->cookie), 6618c2ecf20Sopenharmony_ci &nm.disk_name, &fstr); 6628c2ecf20Sopenharmony_ci if (err) 6638c2ecf20Sopenharmony_ci goto out; 6648c2ecf20Sopenharmony_ci } else { 6658c2ecf20Sopenharmony_ci fstr.len = fname_len(&nm); 6668c2ecf20Sopenharmony_ci fstr.name = fname_name(&nm); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (!dir_emit(ctx, fstr.name, fstr.len, 6708c2ecf20Sopenharmony_ci le64_to_cpu(dent->inum), 6718c2ecf20Sopenharmony_ci vfs_dent_type(dent->type))) { 6728c2ecf20Sopenharmony_ci if (encrypted) 6738c2ecf20Sopenharmony_ci fscrypt_fname_free_buffer(&fstr); 6748c2ecf20Sopenharmony_ci return 0; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* Switch to the next entry */ 6788c2ecf20Sopenharmony_ci key_read(c, &dent->key, &key); 6798c2ecf20Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 6808c2ecf20Sopenharmony_ci if (IS_ERR(dent)) { 6818c2ecf20Sopenharmony_ci err = PTR_ERR(dent); 6828c2ecf20Sopenharmony_ci goto out; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci kfree(file->private_data); 6868c2ecf20Sopenharmony_ci ctx->pos = key_hash_flash(c, &dent->key); 6878c2ecf20Sopenharmony_ci file->private_data = dent; 6888c2ecf20Sopenharmony_ci cond_resched(); 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ciout: 6928c2ecf20Sopenharmony_ci kfree(file->private_data); 6938c2ecf20Sopenharmony_ci file->private_data = NULL; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (encrypted) 6968c2ecf20Sopenharmony_ci fscrypt_fname_free_buffer(&fstr); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (err != -ENOENT) 6998c2ecf20Sopenharmony_ci ubifs_err(c, "cannot find next direntry, error %d", err); 7008c2ecf20Sopenharmony_ci else 7018c2ecf20Sopenharmony_ci /* 7028c2ecf20Sopenharmony_ci * -ENOENT is a non-fatal error in this context, the TNC uses 7038c2ecf20Sopenharmony_ci * it to indicate that the cursor moved past the current directory 7048c2ecf20Sopenharmony_ci * and readdir() has to stop. 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci err = 0; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* 2 is a special value indicating that there are no more direntries */ 7108c2ecf20Sopenharmony_ci ctx->pos = 2; 7118c2ecf20Sopenharmony_ci return err; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* Free saved readdir() state when the directory is closed */ 7158c2ecf20Sopenharmony_cistatic int ubifs_dir_release(struct inode *dir, struct file *file) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci kfree(file->private_data); 7188c2ecf20Sopenharmony_ci file->private_data = NULL; 7198c2ecf20Sopenharmony_ci return 0; 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic int ubifs_link(struct dentry *old_dentry, struct inode *dir, 7238c2ecf20Sopenharmony_ci struct dentry *dentry) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 7268c2ecf20Sopenharmony_ci struct inode *inode = d_inode(old_dentry); 7278c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 7288c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 7298c2ecf20Sopenharmony_ci int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); 7308c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, 7318c2ecf20Sopenharmony_ci .dirtied_ino_d = ALIGN(ui->data_len, 8) }; 7328c2ecf20Sopenharmony_ci struct fscrypt_name nm; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * Budget request settings: new direntry, changing the target inode, 7368c2ecf20Sopenharmony_ci * changing the parent inode. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci dbg_gen("dent '%pd' to ino %lu (nlink %d) in dir ino %lu", 7408c2ecf20Sopenharmony_ci dentry, inode->i_ino, 7418c2ecf20Sopenharmony_ci inode->i_nlink, dir->i_ino); 7428c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(dir)); 7438c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(inode)); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci err = fscrypt_prepare_link(old_dentry, dir, dentry); 7468c2ecf20Sopenharmony_ci if (err) 7478c2ecf20Sopenharmony_ci return err; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); 7508c2ecf20Sopenharmony_ci if (err) 7518c2ecf20Sopenharmony_ci return err; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci err = dbg_check_synced_i_size(c, inode); 7548c2ecf20Sopenharmony_ci if (err) 7558c2ecf20Sopenharmony_ci goto out_fname; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 7588c2ecf20Sopenharmony_ci if (err) 7598c2ecf20Sopenharmony_ci goto out_fname; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci lock_2_inodes(dir, inode); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */ 7648c2ecf20Sopenharmony_ci if (inode->i_nlink == 0) 7658c2ecf20Sopenharmony_ci ubifs_delete_orphan(c, inode->i_ino); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci inc_nlink(inode); 7688c2ecf20Sopenharmony_ci ihold(inode); 7698c2ecf20Sopenharmony_ci inode->i_ctime = current_time(inode); 7708c2ecf20Sopenharmony_ci dir->i_size += sz_change; 7718c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 7728c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 7738c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 7748c2ecf20Sopenharmony_ci if (err) 7758c2ecf20Sopenharmony_ci goto out_cancel; 7768c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 7798c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 7808c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 7818c2ecf20Sopenharmony_ci return 0; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ciout_cancel: 7848c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 7858c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 7868c2ecf20Sopenharmony_ci drop_nlink(inode); 7878c2ecf20Sopenharmony_ci if (inode->i_nlink == 0) 7888c2ecf20Sopenharmony_ci ubifs_add_orphan(c, inode->i_ino); 7898c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 7908c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 7918c2ecf20Sopenharmony_ci iput(inode); 7928c2ecf20Sopenharmony_ciout_fname: 7938c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 7948c2ecf20Sopenharmony_ci return err; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int ubifs_unlink(struct inode *dir, struct dentry *dentry) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 8008c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 8018c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 8028c2ecf20Sopenharmony_ci int err, sz_change, budgeted = 1; 8038c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; 8048c2ecf20Sopenharmony_ci unsigned int saved_nlink = inode->i_nlink; 8058c2ecf20Sopenharmony_ci struct fscrypt_name nm; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* 8088c2ecf20Sopenharmony_ci * Budget request settings: deletion direntry, deletion inode (+1 for 8098c2ecf20Sopenharmony_ci * @dirtied_ino), changing the parent directory inode. If budgeting 8108c2ecf20Sopenharmony_ci * fails, go ahead anyway because we have extra space reserved for 8118c2ecf20Sopenharmony_ci * deletions. 8128c2ecf20Sopenharmony_ci */ 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu", 8158c2ecf20Sopenharmony_ci dentry, inode->i_ino, 8168c2ecf20Sopenharmony_ci inode->i_nlink, dir->i_ino); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); 8198c2ecf20Sopenharmony_ci if (err) 8208c2ecf20Sopenharmony_ci return err; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci err = ubifs_purge_xattrs(inode); 8238c2ecf20Sopenharmony_ci if (err) 8248c2ecf20Sopenharmony_ci return err; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(dir)); 8298c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(inode)); 8308c2ecf20Sopenharmony_ci err = dbg_check_synced_i_size(c, inode); 8318c2ecf20Sopenharmony_ci if (err) 8328c2ecf20Sopenharmony_ci goto out_fname; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 8358c2ecf20Sopenharmony_ci if (err) { 8368c2ecf20Sopenharmony_ci if (err != -ENOSPC) 8378c2ecf20Sopenharmony_ci goto out_fname; 8388c2ecf20Sopenharmony_ci budgeted = 0; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci lock_2_inodes(dir, inode); 8428c2ecf20Sopenharmony_ci inode->i_ctime = current_time(dir); 8438c2ecf20Sopenharmony_ci drop_nlink(inode); 8448c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 8458c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 8468c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 8478c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); 8488c2ecf20Sopenharmony_ci if (err) 8498c2ecf20Sopenharmony_ci goto out_cancel; 8508c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (budgeted) 8538c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 8548c2ecf20Sopenharmony_ci else { 8558c2ecf20Sopenharmony_ci /* We've deleted something - clean the "no space" flags */ 8568c2ecf20Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 8578c2ecf20Sopenharmony_ci smp_wmb(); 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ciout_cancel: 8638c2ecf20Sopenharmony_ci dir->i_size += sz_change; 8648c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 8658c2ecf20Sopenharmony_ci set_nlink(inode, saved_nlink); 8668c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 8678c2ecf20Sopenharmony_ci if (budgeted) 8688c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 8698c2ecf20Sopenharmony_ciout_fname: 8708c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 8718c2ecf20Sopenharmony_ci return err; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/** 8758c2ecf20Sopenharmony_ci * check_dir_empty - check if a directory is empty or not. 8768c2ecf20Sopenharmony_ci * @dir: VFS inode object of the directory to check 8778c2ecf20Sopenharmony_ci * 8788c2ecf20Sopenharmony_ci * This function checks if directory @dir is empty. Returns zero if the 8798c2ecf20Sopenharmony_ci * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes 8808c2ecf20Sopenharmony_ci * in case of of errors. 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ciint ubifs_check_dir_empty(struct inode *dir) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 8858c2ecf20Sopenharmony_ci struct fscrypt_name nm = { 0 }; 8868c2ecf20Sopenharmony_ci struct ubifs_dent_node *dent; 8878c2ecf20Sopenharmony_ci union ubifs_key key; 8888c2ecf20Sopenharmony_ci int err; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci lowest_dent_key(c, &key, dir->i_ino); 8918c2ecf20Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 8928c2ecf20Sopenharmony_ci if (IS_ERR(dent)) { 8938c2ecf20Sopenharmony_ci err = PTR_ERR(dent); 8948c2ecf20Sopenharmony_ci if (err == -ENOENT) 8958c2ecf20Sopenharmony_ci err = 0; 8968c2ecf20Sopenharmony_ci } else { 8978c2ecf20Sopenharmony_ci kfree(dent); 8988c2ecf20Sopenharmony_ci err = -ENOTEMPTY; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci return err; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic int ubifs_rmdir(struct inode *dir, struct dentry *dentry) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 9068c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 9078c2ecf20Sopenharmony_ci int err, sz_change, budgeted = 1; 9088c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 9098c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; 9108c2ecf20Sopenharmony_ci struct fscrypt_name nm; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* 9138c2ecf20Sopenharmony_ci * Budget request settings: deletion direntry, deletion inode and 9148c2ecf20Sopenharmony_ci * changing the parent inode. If budgeting fails, go ahead anyway 9158c2ecf20Sopenharmony_ci * because we have extra space reserved for deletions. 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci dbg_gen("directory '%pd', ino %lu in dir ino %lu", dentry, 9198c2ecf20Sopenharmony_ci inode->i_ino, dir->i_ino); 9208c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(dir)); 9218c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(inode)); 9228c2ecf20Sopenharmony_ci err = ubifs_check_dir_empty(d_inode(dentry)); 9238c2ecf20Sopenharmony_ci if (err) 9248c2ecf20Sopenharmony_ci return err; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); 9278c2ecf20Sopenharmony_ci if (err) 9288c2ecf20Sopenharmony_ci return err; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci err = ubifs_purge_xattrs(inode); 9318c2ecf20Sopenharmony_ci if (err) 9328c2ecf20Sopenharmony_ci return err; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 9378c2ecf20Sopenharmony_ci if (err) { 9388c2ecf20Sopenharmony_ci if (err != -ENOSPC) 9398c2ecf20Sopenharmony_ci goto out_fname; 9408c2ecf20Sopenharmony_ci budgeted = 0; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci lock_2_inodes(dir, inode); 9448c2ecf20Sopenharmony_ci inode->i_ctime = current_time(dir); 9458c2ecf20Sopenharmony_ci clear_nlink(inode); 9468c2ecf20Sopenharmony_ci drop_nlink(dir); 9478c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 9488c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 9498c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 9508c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); 9518c2ecf20Sopenharmony_ci if (err) 9528c2ecf20Sopenharmony_ci goto out_cancel; 9538c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci if (budgeted) 9568c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 9578c2ecf20Sopenharmony_ci else { 9588c2ecf20Sopenharmony_ci /* We've deleted something - clean the "no space" flags */ 9598c2ecf20Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 9608c2ecf20Sopenharmony_ci smp_wmb(); 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 9638c2ecf20Sopenharmony_ci return 0; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ciout_cancel: 9668c2ecf20Sopenharmony_ci dir->i_size += sz_change; 9678c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 9688c2ecf20Sopenharmony_ci inc_nlink(dir); 9698c2ecf20Sopenharmony_ci set_nlink(inode, 2); 9708c2ecf20Sopenharmony_ci unlock_2_inodes(dir, inode); 9718c2ecf20Sopenharmony_ci if (budgeted) 9728c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 9738c2ecf20Sopenharmony_ciout_fname: 9748c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 9758c2ecf20Sopenharmony_ci return err; 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci struct inode *inode; 9818c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 9828c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 9838c2ecf20Sopenharmony_ci int err, sz_change; 9848c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 9858c2ecf20Sopenharmony_ci .dirtied_ino = 1}; 9868c2ecf20Sopenharmony_ci struct fscrypt_name nm; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci /* 9898c2ecf20Sopenharmony_ci * Budget request settings: new inode, new direntry and changing parent 9908c2ecf20Sopenharmony_ci * directory inode. 9918c2ecf20Sopenharmony_ci */ 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 9948c2ecf20Sopenharmony_ci dentry, mode, dir->i_ino); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 9978c2ecf20Sopenharmony_ci if (err) 9988c2ecf20Sopenharmony_ci return err; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 10018c2ecf20Sopenharmony_ci if (err) 10028c2ecf20Sopenharmony_ci goto out_budg; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci inode = ubifs_new_inode(c, dir, S_IFDIR | mode); 10078c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 10088c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 10098c2ecf20Sopenharmony_ci goto out_fname; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 10138c2ecf20Sopenharmony_ci if (err) 10148c2ecf20Sopenharmony_ci goto out_inode; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 10178c2ecf20Sopenharmony_ci insert_inode_hash(inode); 10188c2ecf20Sopenharmony_ci inc_nlink(inode); 10198c2ecf20Sopenharmony_ci inc_nlink(dir); 10208c2ecf20Sopenharmony_ci dir->i_size += sz_change; 10218c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 10228c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 10238c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 10248c2ecf20Sopenharmony_ci if (err) { 10258c2ecf20Sopenharmony_ci ubifs_err(c, "cannot create directory, error %d", err); 10268c2ecf20Sopenharmony_ci goto out_cancel; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 10318c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 10328c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 10338c2ecf20Sopenharmony_ci return 0; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ciout_cancel: 10368c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 10378c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 10388c2ecf20Sopenharmony_ci drop_nlink(dir); 10398c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 10408c2ecf20Sopenharmony_ciout_inode: 10418c2ecf20Sopenharmony_ci make_bad_inode(inode); 10428c2ecf20Sopenharmony_ci iput(inode); 10438c2ecf20Sopenharmony_ciout_fname: 10448c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 10458c2ecf20Sopenharmony_ciout_budg: 10468c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 10478c2ecf20Sopenharmony_ci return err; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic int ubifs_mknod(struct inode *dir, struct dentry *dentry, 10518c2ecf20Sopenharmony_ci umode_t mode, dev_t rdev) 10528c2ecf20Sopenharmony_ci{ 10538c2ecf20Sopenharmony_ci struct inode *inode; 10548c2ecf20Sopenharmony_ci struct ubifs_inode *ui; 10558c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 10568c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 10578c2ecf20Sopenharmony_ci union ubifs_dev_desc *dev = NULL; 10588c2ecf20Sopenharmony_ci int sz_change; 10598c2ecf20Sopenharmony_ci int err, devlen = 0; 10608c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 10618c2ecf20Sopenharmony_ci .dirtied_ino = 1 }; 10628c2ecf20Sopenharmony_ci struct fscrypt_name nm; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* 10658c2ecf20Sopenharmony_ci * Budget request settings: new inode, new direntry and changing parent 10668c2ecf20Sopenharmony_ci * directory inode. 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (S_ISBLK(mode) || S_ISCHR(mode)) { 10728c2ecf20Sopenharmony_ci dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); 10738c2ecf20Sopenharmony_ci if (!dev) 10748c2ecf20Sopenharmony_ci return -ENOMEM; 10758c2ecf20Sopenharmony_ci devlen = ubifs_encode_dev(dev, rdev); 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci req.new_ino_d = ALIGN(devlen, 8); 10798c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 10808c2ecf20Sopenharmony_ci if (err) { 10818c2ecf20Sopenharmony_ci kfree(dev); 10828c2ecf20Sopenharmony_ci return err; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 10868c2ecf20Sopenharmony_ci if (err) { 10878c2ecf20Sopenharmony_ci kfree(dev); 10888c2ecf20Sopenharmony_ci goto out_budg; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode); 10948c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 10958c2ecf20Sopenharmony_ci kfree(dev); 10968c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 10978c2ecf20Sopenharmony_ci goto out_fname; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci init_special_inode(inode, inode->i_mode, rdev); 11018c2ecf20Sopenharmony_ci inode->i_size = ubifs_inode(inode)->ui_size = devlen; 11028c2ecf20Sopenharmony_ci ui = ubifs_inode(inode); 11038c2ecf20Sopenharmony_ci ui->data = dev; 11048c2ecf20Sopenharmony_ci ui->data_len = devlen; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 11078c2ecf20Sopenharmony_ci if (err) 11088c2ecf20Sopenharmony_ci goto out_inode; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 11118c2ecf20Sopenharmony_ci dir->i_size += sz_change; 11128c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 11138c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 11148c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 11158c2ecf20Sopenharmony_ci if (err) 11168c2ecf20Sopenharmony_ci goto out_cancel; 11178c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 11208c2ecf20Sopenharmony_ci insert_inode_hash(inode); 11218c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 11228c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 11238c2ecf20Sopenharmony_ci return 0; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ciout_cancel: 11268c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 11278c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 11288c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 11298c2ecf20Sopenharmony_ciout_inode: 11308c2ecf20Sopenharmony_ci /* Free inode->i_link before inode is marked as bad. */ 11318c2ecf20Sopenharmony_ci fscrypt_free_inode(inode); 11328c2ecf20Sopenharmony_ci make_bad_inode(inode); 11338c2ecf20Sopenharmony_ci iput(inode); 11348c2ecf20Sopenharmony_ciout_fname: 11358c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 11368c2ecf20Sopenharmony_ciout_budg: 11378c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 11388c2ecf20Sopenharmony_ci return err; 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic int ubifs_symlink(struct inode *dir, struct dentry *dentry, 11428c2ecf20Sopenharmony_ci const char *symname) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci struct inode *inode; 11458c2ecf20Sopenharmony_ci struct ubifs_inode *ui; 11468c2ecf20Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 11478c2ecf20Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 11488c2ecf20Sopenharmony_ci int err, sz_change, len = strlen(symname); 11498c2ecf20Sopenharmony_ci struct fscrypt_str disk_link; 11508c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 11518c2ecf20Sopenharmony_ci .dirtied_ino = 1 }; 11528c2ecf20Sopenharmony_ci struct fscrypt_name nm; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, 11558c2ecf20Sopenharmony_ci symname, dir->i_ino); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA, 11588c2ecf20Sopenharmony_ci &disk_link); 11598c2ecf20Sopenharmony_ci if (err) 11608c2ecf20Sopenharmony_ci return err; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * Budget request settings: new inode, new direntry and changing parent 11648c2ecf20Sopenharmony_ci * directory inode. 11658c2ecf20Sopenharmony_ci */ 11668c2ecf20Sopenharmony_ci req.new_ino_d = ALIGN(disk_link.len - 1, 8); 11678c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 11688c2ecf20Sopenharmony_ci if (err) 11698c2ecf20Sopenharmony_ci return err; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 11728c2ecf20Sopenharmony_ci if (err) 11738c2ecf20Sopenharmony_ci goto out_budg; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); 11788c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 11798c2ecf20Sopenharmony_ci err = PTR_ERR(inode); 11808c2ecf20Sopenharmony_ci goto out_fname; 11818c2ecf20Sopenharmony_ci } 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci ui = ubifs_inode(inode); 11848c2ecf20Sopenharmony_ci ui->data = kmalloc(disk_link.len, GFP_NOFS); 11858c2ecf20Sopenharmony_ci if (!ui->data) { 11868c2ecf20Sopenharmony_ci err = -ENOMEM; 11878c2ecf20Sopenharmony_ci goto out_inode; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(inode)) { 11918c2ecf20Sopenharmony_ci disk_link.name = ui->data; /* encrypt directly into ui->data */ 11928c2ecf20Sopenharmony_ci err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); 11938c2ecf20Sopenharmony_ci if (err) 11948c2ecf20Sopenharmony_ci goto out_inode; 11958c2ecf20Sopenharmony_ci } else { 11968c2ecf20Sopenharmony_ci memcpy(ui->data, disk_link.name, disk_link.len); 11978c2ecf20Sopenharmony_ci inode->i_link = ui->data; 11988c2ecf20Sopenharmony_ci } 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* 12018c2ecf20Sopenharmony_ci * The terminating zero byte is not written to the flash media and it 12028c2ecf20Sopenharmony_ci * is put just to make later in-memory string processing simpler. Thus, 12038c2ecf20Sopenharmony_ci * data length is @disk_link.len - 1, not @disk_link.len. 12048c2ecf20Sopenharmony_ci */ 12058c2ecf20Sopenharmony_ci ui->data_len = disk_link.len - 1; 12068c2ecf20Sopenharmony_ci inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 12098c2ecf20Sopenharmony_ci if (err) 12108c2ecf20Sopenharmony_ci goto out_inode; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 12138c2ecf20Sopenharmony_ci dir->i_size += sz_change; 12148c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 12158c2ecf20Sopenharmony_ci dir->i_mtime = dir->i_ctime = inode->i_ctime; 12168c2ecf20Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 12178c2ecf20Sopenharmony_ci if (err) 12188c2ecf20Sopenharmony_ci goto out_cancel; 12198c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci insert_inode_hash(inode); 12228c2ecf20Sopenharmony_ci d_instantiate(dentry, inode); 12238c2ecf20Sopenharmony_ci err = 0; 12248c2ecf20Sopenharmony_ci goto out_fname; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ciout_cancel: 12278c2ecf20Sopenharmony_ci dir->i_size -= sz_change; 12288c2ecf20Sopenharmony_ci dir_ui->ui_size = dir->i_size; 12298c2ecf20Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 12308c2ecf20Sopenharmony_ciout_inode: 12318c2ecf20Sopenharmony_ci /* Free inode->i_link before inode is marked as bad. */ 12328c2ecf20Sopenharmony_ci fscrypt_free_inode(inode); 12338c2ecf20Sopenharmony_ci make_bad_inode(inode); 12348c2ecf20Sopenharmony_ci iput(inode); 12358c2ecf20Sopenharmony_ciout_fname: 12368c2ecf20Sopenharmony_ci fscrypt_free_filename(&nm); 12378c2ecf20Sopenharmony_ciout_budg: 12388c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 12398c2ecf20Sopenharmony_ci return err; 12408c2ecf20Sopenharmony_ci} 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci/** 12438c2ecf20Sopenharmony_ci * lock_4_inodes - a wrapper for locking three UBIFS inodes. 12448c2ecf20Sopenharmony_ci * @inode1: first inode 12458c2ecf20Sopenharmony_ci * @inode2: second inode 12468c2ecf20Sopenharmony_ci * @inode3: third inode 12478c2ecf20Sopenharmony_ci * @inode4: fouth inode 12488c2ecf20Sopenharmony_ci * 12498c2ecf20Sopenharmony_ci * This function is used for 'ubifs_rename()' and @inode1 may be the same as 12508c2ecf20Sopenharmony_ci * @inode2 whereas @inode3 and @inode4 may be %NULL. 12518c2ecf20Sopenharmony_ci * 12528c2ecf20Sopenharmony_ci * We do not implement any tricks to guarantee strict lock ordering, because 12538c2ecf20Sopenharmony_ci * VFS has already done it for us on the @i_mutex. So this is just a simple 12548c2ecf20Sopenharmony_ci * wrapper function. 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_cistatic void lock_4_inodes(struct inode *inode1, struct inode *inode2, 12578c2ecf20Sopenharmony_ci struct inode *inode3, struct inode *inode4) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); 12608c2ecf20Sopenharmony_ci if (inode2 != inode1) 12618c2ecf20Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); 12628c2ecf20Sopenharmony_ci if (inode3) 12638c2ecf20Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3); 12648c2ecf20Sopenharmony_ci if (inode4) 12658c2ecf20Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4); 12668c2ecf20Sopenharmony_ci} 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci/** 12698c2ecf20Sopenharmony_ci * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename. 12708c2ecf20Sopenharmony_ci * @inode1: first inode 12718c2ecf20Sopenharmony_ci * @inode2: second inode 12728c2ecf20Sopenharmony_ci * @inode3: third inode 12738c2ecf20Sopenharmony_ci * @inode4: fouth inode 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_cistatic void unlock_4_inodes(struct inode *inode1, struct inode *inode2, 12768c2ecf20Sopenharmony_ci struct inode *inode3, struct inode *inode4) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci if (inode4) 12798c2ecf20Sopenharmony_ci mutex_unlock(&ubifs_inode(inode4)->ui_mutex); 12808c2ecf20Sopenharmony_ci if (inode3) 12818c2ecf20Sopenharmony_ci mutex_unlock(&ubifs_inode(inode3)->ui_mutex); 12828c2ecf20Sopenharmony_ci if (inode1 != inode2) 12838c2ecf20Sopenharmony_ci mutex_unlock(&ubifs_inode(inode2)->ui_mutex); 12848c2ecf20Sopenharmony_ci mutex_unlock(&ubifs_inode(inode1)->ui_mutex); 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic int do_rename(struct inode *old_dir, struct dentry *old_dentry, 12888c2ecf20Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 12898c2ecf20Sopenharmony_ci unsigned int flags) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci struct ubifs_info *c = old_dir->i_sb->s_fs_info; 12928c2ecf20Sopenharmony_ci struct inode *old_inode = d_inode(old_dentry); 12938c2ecf20Sopenharmony_ci struct inode *new_inode = d_inode(new_dentry); 12948c2ecf20Sopenharmony_ci struct inode *whiteout = NULL; 12958c2ecf20Sopenharmony_ci struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); 12968c2ecf20Sopenharmony_ci struct ubifs_inode *whiteout_ui = NULL; 12978c2ecf20Sopenharmony_ci int err, release, sync = 0, move = (new_dir != old_dir); 12988c2ecf20Sopenharmony_ci int is_dir = S_ISDIR(old_inode->i_mode); 12998c2ecf20Sopenharmony_ci int unlink = !!new_inode, new_sz, old_sz; 13008c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, 13018c2ecf20Sopenharmony_ci .dirtied_ino = 3 }; 13028c2ecf20Sopenharmony_ci struct ubifs_budget_req ino_req = { .dirtied_ino = 1, 13038c2ecf20Sopenharmony_ci .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; 13048c2ecf20Sopenharmony_ci struct ubifs_budget_req wht_req; 13058c2ecf20Sopenharmony_ci struct timespec64 time; 13068c2ecf20Sopenharmony_ci unsigned int saved_nlink; 13078c2ecf20Sopenharmony_ci struct fscrypt_name old_nm, new_nm; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci /* 13108c2ecf20Sopenharmony_ci * Budget request settings: 13118c2ecf20Sopenharmony_ci * req: deletion direntry, new direntry, removing the old inode, 13128c2ecf20Sopenharmony_ci * and changing old and new parent directory inodes. 13138c2ecf20Sopenharmony_ci * 13148c2ecf20Sopenharmony_ci * wht_req: new whiteout inode for RENAME_WHITEOUT. 13158c2ecf20Sopenharmony_ci * 13168c2ecf20Sopenharmony_ci * ino_req: marks the target inode as dirty and does not write it. 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x", 13208c2ecf20Sopenharmony_ci old_dentry, old_inode->i_ino, old_dir->i_ino, 13218c2ecf20Sopenharmony_ci new_dentry, new_dir->i_ino, flags); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (unlink) { 13248c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(new_inode)); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Budget for old inode's data when its nlink > 1. */ 13278c2ecf20Sopenharmony_ci req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8); 13288c2ecf20Sopenharmony_ci err = ubifs_purge_xattrs(new_inode); 13298c2ecf20Sopenharmony_ci if (err) 13308c2ecf20Sopenharmony_ci return err; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (unlink && is_dir) { 13348c2ecf20Sopenharmony_ci err = ubifs_check_dir_empty(new_inode); 13358c2ecf20Sopenharmony_ci if (err) 13368c2ecf20Sopenharmony_ci return err; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm); 13408c2ecf20Sopenharmony_ci if (err) 13418c2ecf20Sopenharmony_ci return err; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm); 13448c2ecf20Sopenharmony_ci if (err) { 13458c2ecf20Sopenharmony_ci fscrypt_free_filename(&old_nm); 13468c2ecf20Sopenharmony_ci return err; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci new_sz = CALC_DENT_SIZE(fname_len(&new_nm)); 13508c2ecf20Sopenharmony_ci old_sz = CALC_DENT_SIZE(fname_len(&old_nm)); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 13538c2ecf20Sopenharmony_ci if (err) { 13548c2ecf20Sopenharmony_ci fscrypt_free_filename(&old_nm); 13558c2ecf20Sopenharmony_ci fscrypt_free_filename(&new_nm); 13568c2ecf20Sopenharmony_ci return err; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &ino_req); 13598c2ecf20Sopenharmony_ci if (err) { 13608c2ecf20Sopenharmony_ci fscrypt_free_filename(&old_nm); 13618c2ecf20Sopenharmony_ci fscrypt_free_filename(&new_nm); 13628c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 13638c2ecf20Sopenharmony_ci return err; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (flags & RENAME_WHITEOUT) { 13678c2ecf20Sopenharmony_ci union ubifs_dev_desc *dev = NULL; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); 13708c2ecf20Sopenharmony_ci if (!dev) { 13718c2ecf20Sopenharmony_ci err = -ENOMEM; 13728c2ecf20Sopenharmony_ci goto out_release; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* 13768c2ecf20Sopenharmony_ci * The whiteout inode without dentry is pinned in memory, 13778c2ecf20Sopenharmony_ci * umount won't happen during rename process because we 13788c2ecf20Sopenharmony_ci * got parent dentry. 13798c2ecf20Sopenharmony_ci */ 13808c2ecf20Sopenharmony_ci whiteout = create_whiteout(old_dir, old_dentry); 13818c2ecf20Sopenharmony_ci if (IS_ERR(whiteout)) { 13828c2ecf20Sopenharmony_ci err = PTR_ERR(whiteout); 13838c2ecf20Sopenharmony_ci kfree(dev); 13848c2ecf20Sopenharmony_ci goto out_release; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci whiteout_ui = ubifs_inode(whiteout); 13888c2ecf20Sopenharmony_ci whiteout_ui->data = dev; 13898c2ecf20Sopenharmony_ci whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); 13908c2ecf20Sopenharmony_ci ubifs_assert(c, !whiteout_ui->dirty); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci memset(&wht_req, 0, sizeof(struct ubifs_budget_req)); 13938c2ecf20Sopenharmony_ci wht_req.new_ino = 1; 13948c2ecf20Sopenharmony_ci wht_req.new_ino_d = ALIGN(whiteout_ui->data_len, 8); 13958c2ecf20Sopenharmony_ci /* 13968c2ecf20Sopenharmony_ci * To avoid deadlock between space budget (holds ui_mutex and 13978c2ecf20Sopenharmony_ci * waits wb work) and writeback work(waits ui_mutex), do space 13988c2ecf20Sopenharmony_ci * budget before ubifs inodes locked. 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &wht_req); 14018c2ecf20Sopenharmony_ci if (err) { 14028c2ecf20Sopenharmony_ci /* 14038c2ecf20Sopenharmony_ci * Whiteout inode can not be written on flash by 14048c2ecf20Sopenharmony_ci * ubifs_jnl_write_inode(), because it's neither 14058c2ecf20Sopenharmony_ci * dirty nor zero-nlink. 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_ci iput(whiteout); 14088c2ecf20Sopenharmony_ci goto out_release; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci /* Add the old_dentry size to the old_dir size. */ 14128c2ecf20Sopenharmony_ci old_sz -= CALC_DENT_SIZE(fname_len(&old_nm)); 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci lock_4_inodes(old_dir, new_dir, new_inode, whiteout); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* 14188c2ecf20Sopenharmony_ci * Like most other Unix systems, set the @i_ctime for inodes on a 14198c2ecf20Sopenharmony_ci * rename. 14208c2ecf20Sopenharmony_ci */ 14218c2ecf20Sopenharmony_ci time = current_time(old_dir); 14228c2ecf20Sopenharmony_ci old_inode->i_ctime = time; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci /* We must adjust parent link count when renaming directories */ 14258c2ecf20Sopenharmony_ci if (is_dir) { 14268c2ecf20Sopenharmony_ci if (move) { 14278c2ecf20Sopenharmony_ci /* 14288c2ecf20Sopenharmony_ci * @old_dir loses a link because we are moving 14298c2ecf20Sopenharmony_ci * @old_inode to a different directory. 14308c2ecf20Sopenharmony_ci */ 14318c2ecf20Sopenharmony_ci drop_nlink(old_dir); 14328c2ecf20Sopenharmony_ci /* 14338c2ecf20Sopenharmony_ci * @new_dir only gains a link if we are not also 14348c2ecf20Sopenharmony_ci * overwriting an existing directory. 14358c2ecf20Sopenharmony_ci */ 14368c2ecf20Sopenharmony_ci if (!unlink) 14378c2ecf20Sopenharmony_ci inc_nlink(new_dir); 14388c2ecf20Sopenharmony_ci } else { 14398c2ecf20Sopenharmony_ci /* 14408c2ecf20Sopenharmony_ci * @old_inode is not moving to a different directory, 14418c2ecf20Sopenharmony_ci * but @old_dir still loses a link if we are 14428c2ecf20Sopenharmony_ci * overwriting an existing directory. 14438c2ecf20Sopenharmony_ci */ 14448c2ecf20Sopenharmony_ci if (unlink) 14458c2ecf20Sopenharmony_ci drop_nlink(old_dir); 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci old_dir->i_size -= old_sz; 14508c2ecf20Sopenharmony_ci ubifs_inode(old_dir)->ui_size = old_dir->i_size; 14518c2ecf20Sopenharmony_ci old_dir->i_mtime = old_dir->i_ctime = time; 14528c2ecf20Sopenharmony_ci new_dir->i_mtime = new_dir->i_ctime = time; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* 14558c2ecf20Sopenharmony_ci * And finally, if we unlinked a direntry which happened to have the 14568c2ecf20Sopenharmony_ci * same name as the moved direntry, we have to decrement @i_nlink of 14578c2ecf20Sopenharmony_ci * the unlinked inode and change its ctime. 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci if (unlink) { 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * Directories cannot have hard-links, so if this is a 14628c2ecf20Sopenharmony_ci * directory, just clear @i_nlink. 14638c2ecf20Sopenharmony_ci */ 14648c2ecf20Sopenharmony_ci saved_nlink = new_inode->i_nlink; 14658c2ecf20Sopenharmony_ci if (is_dir) 14668c2ecf20Sopenharmony_ci clear_nlink(new_inode); 14678c2ecf20Sopenharmony_ci else 14688c2ecf20Sopenharmony_ci drop_nlink(new_inode); 14698c2ecf20Sopenharmony_ci new_inode->i_ctime = time; 14708c2ecf20Sopenharmony_ci } else { 14718c2ecf20Sopenharmony_ci new_dir->i_size += new_sz; 14728c2ecf20Sopenharmony_ci ubifs_inode(new_dir)->ui_size = new_dir->i_size; 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* 14768c2ecf20Sopenharmony_ci * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode 14778c2ecf20Sopenharmony_ci * is dirty, because this will be done later on at the end of 14788c2ecf20Sopenharmony_ci * 'ubifs_rename()'. 14798c2ecf20Sopenharmony_ci */ 14808c2ecf20Sopenharmony_ci if (IS_SYNC(old_inode)) { 14818c2ecf20Sopenharmony_ci sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); 14828c2ecf20Sopenharmony_ci if (unlink && IS_SYNC(new_inode)) 14838c2ecf20Sopenharmony_ci sync = 1; 14848c2ecf20Sopenharmony_ci /* 14858c2ecf20Sopenharmony_ci * S_SYNC flag of whiteout inherits from the old_dir, and we 14868c2ecf20Sopenharmony_ci * have already checked the old dir inode. So there is no need 14878c2ecf20Sopenharmony_ci * to check whiteout. 14888c2ecf20Sopenharmony_ci */ 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir, 14928c2ecf20Sopenharmony_ci new_inode, &new_nm, whiteout, sync); 14938c2ecf20Sopenharmony_ci if (err) 14948c2ecf20Sopenharmony_ci goto out_cancel; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); 14978c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci if (whiteout) { 15008c2ecf20Sopenharmony_ci ubifs_release_budget(c, &wht_req); 15018c2ecf20Sopenharmony_ci iput(whiteout); 15028c2ecf20Sopenharmony_ci } 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci mutex_lock(&old_inode_ui->ui_mutex); 15058c2ecf20Sopenharmony_ci release = old_inode_ui->dirty; 15068c2ecf20Sopenharmony_ci mark_inode_dirty_sync(old_inode); 15078c2ecf20Sopenharmony_ci mutex_unlock(&old_inode_ui->ui_mutex); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (release) 15108c2ecf20Sopenharmony_ci ubifs_release_budget(c, &ino_req); 15118c2ecf20Sopenharmony_ci if (IS_SYNC(old_inode)) 15128c2ecf20Sopenharmony_ci /* 15138c2ecf20Sopenharmony_ci * Rename finished here. Although old inode cannot be updated 15148c2ecf20Sopenharmony_ci * on flash, old ctime is not a big problem, don't return err 15158c2ecf20Sopenharmony_ci * code to userspace. 15168c2ecf20Sopenharmony_ci */ 15178c2ecf20Sopenharmony_ci old_inode->i_sb->s_op->write_inode(old_inode, NULL); 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci fscrypt_free_filename(&old_nm); 15208c2ecf20Sopenharmony_ci fscrypt_free_filename(&new_nm); 15218c2ecf20Sopenharmony_ci return 0; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ciout_cancel: 15248c2ecf20Sopenharmony_ci if (unlink) { 15258c2ecf20Sopenharmony_ci set_nlink(new_inode, saved_nlink); 15268c2ecf20Sopenharmony_ci } else { 15278c2ecf20Sopenharmony_ci new_dir->i_size -= new_sz; 15288c2ecf20Sopenharmony_ci ubifs_inode(new_dir)->ui_size = new_dir->i_size; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci old_dir->i_size += old_sz; 15318c2ecf20Sopenharmony_ci ubifs_inode(old_dir)->ui_size = old_dir->i_size; 15328c2ecf20Sopenharmony_ci if (is_dir) { 15338c2ecf20Sopenharmony_ci if (move) { 15348c2ecf20Sopenharmony_ci inc_nlink(old_dir); 15358c2ecf20Sopenharmony_ci if (!unlink) 15368c2ecf20Sopenharmony_ci drop_nlink(new_dir); 15378c2ecf20Sopenharmony_ci } else { 15388c2ecf20Sopenharmony_ci if (unlink) 15398c2ecf20Sopenharmony_ci inc_nlink(old_dir); 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); 15438c2ecf20Sopenharmony_ci if (whiteout) { 15448c2ecf20Sopenharmony_ci ubifs_release_budget(c, &wht_req); 15458c2ecf20Sopenharmony_ci iput(whiteout); 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ciout_release: 15488c2ecf20Sopenharmony_ci ubifs_release_budget(c, &ino_req); 15498c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 15508c2ecf20Sopenharmony_ci fscrypt_free_filename(&old_nm); 15518c2ecf20Sopenharmony_ci fscrypt_free_filename(&new_nm); 15528c2ecf20Sopenharmony_ci return err; 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_cistatic int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, 15568c2ecf20Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci struct ubifs_info *c = old_dir->i_sb->s_fs_info; 15598c2ecf20Sopenharmony_ci struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, 15608c2ecf20Sopenharmony_ci .dirtied_ino = 2 }; 15618c2ecf20Sopenharmony_ci int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); 15628c2ecf20Sopenharmony_ci struct inode *fst_inode = d_inode(old_dentry); 15638c2ecf20Sopenharmony_ci struct inode *snd_inode = d_inode(new_dentry); 15648c2ecf20Sopenharmony_ci struct timespec64 time; 15658c2ecf20Sopenharmony_ci int err; 15668c2ecf20Sopenharmony_ci struct fscrypt_name fst_nm, snd_nm; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci ubifs_assert(c, fst_inode && snd_inode); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm); 15718c2ecf20Sopenharmony_ci if (err) 15728c2ecf20Sopenharmony_ci return err; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &snd_nm); 15758c2ecf20Sopenharmony_ci if (err) { 15768c2ecf20Sopenharmony_ci fscrypt_free_filename(&fst_nm); 15778c2ecf20Sopenharmony_ci return err; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci err = ubifs_budget_space(c, &req); 15818c2ecf20Sopenharmony_ci if (err) 15828c2ecf20Sopenharmony_ci goto out; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci lock_4_inodes(old_dir, new_dir, NULL, NULL); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci time = current_time(old_dir); 15878c2ecf20Sopenharmony_ci fst_inode->i_ctime = time; 15888c2ecf20Sopenharmony_ci snd_inode->i_ctime = time; 15898c2ecf20Sopenharmony_ci old_dir->i_mtime = old_dir->i_ctime = time; 15908c2ecf20Sopenharmony_ci new_dir->i_mtime = new_dir->i_ctime = time; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (old_dir != new_dir) { 15938c2ecf20Sopenharmony_ci if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { 15948c2ecf20Sopenharmony_ci inc_nlink(new_dir); 15958c2ecf20Sopenharmony_ci drop_nlink(old_dir); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { 15988c2ecf20Sopenharmony_ci drop_nlink(new_dir); 15998c2ecf20Sopenharmony_ci inc_nlink(old_dir); 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci } 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir, 16048c2ecf20Sopenharmony_ci snd_inode, &snd_nm, sync); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci unlock_4_inodes(old_dir, new_dir, NULL, NULL); 16078c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ciout: 16108c2ecf20Sopenharmony_ci fscrypt_free_filename(&fst_nm); 16118c2ecf20Sopenharmony_ci fscrypt_free_filename(&snd_nm); 16128c2ecf20Sopenharmony_ci return err; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, 16168c2ecf20Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 16178c2ecf20Sopenharmony_ci unsigned int flags) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci int err; 16208c2ecf20Sopenharmony_ci struct ubifs_info *c = old_dir->i_sb->s_fs_info; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE)) 16238c2ecf20Sopenharmony_ci return -EINVAL; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(old_dir)); 16268c2ecf20Sopenharmony_ci ubifs_assert(c, inode_is_locked(new_dir)); 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry, 16298c2ecf20Sopenharmony_ci flags); 16308c2ecf20Sopenharmony_ci if (err) 16318c2ecf20Sopenharmony_ci return err; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (flags & RENAME_EXCHANGE) 16348c2ecf20Sopenharmony_ci return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags); 16378c2ecf20Sopenharmony_ci} 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ciint ubifs_getattr(const struct path *path, struct kstat *stat, 16408c2ecf20Sopenharmony_ci u32 request_mask, unsigned int flags) 16418c2ecf20Sopenharmony_ci{ 16428c2ecf20Sopenharmony_ci loff_t size; 16438c2ecf20Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 16448c2ecf20Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci mutex_lock(&ui->ui_mutex); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci if (ui->flags & UBIFS_APPEND_FL) 16498c2ecf20Sopenharmony_ci stat->attributes |= STATX_ATTR_APPEND; 16508c2ecf20Sopenharmony_ci if (ui->flags & UBIFS_COMPR_FL) 16518c2ecf20Sopenharmony_ci stat->attributes |= STATX_ATTR_COMPRESSED; 16528c2ecf20Sopenharmony_ci if (ui->flags & UBIFS_CRYPT_FL) 16538c2ecf20Sopenharmony_ci stat->attributes |= STATX_ATTR_ENCRYPTED; 16548c2ecf20Sopenharmony_ci if (ui->flags & UBIFS_IMMUTABLE_FL) 16558c2ecf20Sopenharmony_ci stat->attributes |= STATX_ATTR_IMMUTABLE; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci stat->attributes_mask |= (STATX_ATTR_APPEND | 16588c2ecf20Sopenharmony_ci STATX_ATTR_COMPRESSED | 16598c2ecf20Sopenharmony_ci STATX_ATTR_ENCRYPTED | 16608c2ecf20Sopenharmony_ci STATX_ATTR_IMMUTABLE); 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci generic_fillattr(inode, stat); 16638c2ecf20Sopenharmony_ci stat->blksize = UBIFS_BLOCK_SIZE; 16648c2ecf20Sopenharmony_ci stat->size = ui->ui_size; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci /* 16678c2ecf20Sopenharmony_ci * Unfortunately, the 'stat()' system call was designed for block 16688c2ecf20Sopenharmony_ci * device based file systems, and it is not appropriate for UBIFS, 16698c2ecf20Sopenharmony_ci * because UBIFS does not have notion of "block". For example, it is 16708c2ecf20Sopenharmony_ci * difficult to tell how many block a directory takes - it actually 16718c2ecf20Sopenharmony_ci * takes less than 300 bytes, but we have to round it to block size, 16728c2ecf20Sopenharmony_ci * which introduces large mistake. This makes utilities like 'du' to 16738c2ecf20Sopenharmony_ci * report completely senseless numbers. This is the reason why UBIFS 16748c2ecf20Sopenharmony_ci * goes the same way as JFFS2 - it reports zero blocks for everything 16758c2ecf20Sopenharmony_ci * but regular files, which makes more sense than reporting completely 16768c2ecf20Sopenharmony_ci * wrong sizes. 16778c2ecf20Sopenharmony_ci */ 16788c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 16798c2ecf20Sopenharmony_ci size = ui->xattr_size; 16808c2ecf20Sopenharmony_ci size += stat->size; 16818c2ecf20Sopenharmony_ci size = ALIGN(size, UBIFS_BLOCK_SIZE); 16828c2ecf20Sopenharmony_ci /* 16838c2ecf20Sopenharmony_ci * Note, user-space expects 512-byte blocks count irrespectively 16848c2ecf20Sopenharmony_ci * of what was reported in @stat->size. 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_ci stat->blocks = size >> 9; 16878c2ecf20Sopenharmony_ci } else 16888c2ecf20Sopenharmony_ci stat->blocks = 0; 16898c2ecf20Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 16908c2ecf20Sopenharmony_ci return 0; 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_cistatic int ubifs_dir_open(struct inode *dir, struct file *file) 16948c2ecf20Sopenharmony_ci{ 16958c2ecf20Sopenharmony_ci if (IS_ENCRYPTED(dir)) 16968c2ecf20Sopenharmony_ci return fscrypt_get_encryption_info(dir) ? -EACCES : 0; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci return 0; 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ciconst struct inode_operations ubifs_dir_inode_operations = { 17028c2ecf20Sopenharmony_ci .lookup = ubifs_lookup, 17038c2ecf20Sopenharmony_ci .create = ubifs_create, 17048c2ecf20Sopenharmony_ci .link = ubifs_link, 17058c2ecf20Sopenharmony_ci .symlink = ubifs_symlink, 17068c2ecf20Sopenharmony_ci .unlink = ubifs_unlink, 17078c2ecf20Sopenharmony_ci .mkdir = ubifs_mkdir, 17088c2ecf20Sopenharmony_ci .rmdir = ubifs_rmdir, 17098c2ecf20Sopenharmony_ci .mknod = ubifs_mknod, 17108c2ecf20Sopenharmony_ci .rename = ubifs_rename, 17118c2ecf20Sopenharmony_ci .setattr = ubifs_setattr, 17128c2ecf20Sopenharmony_ci .getattr = ubifs_getattr, 17138c2ecf20Sopenharmony_ci#ifdef CONFIG_UBIFS_FS_XATTR 17148c2ecf20Sopenharmony_ci .listxattr = ubifs_listxattr, 17158c2ecf20Sopenharmony_ci#endif 17168c2ecf20Sopenharmony_ci .update_time = ubifs_update_time, 17178c2ecf20Sopenharmony_ci .tmpfile = ubifs_tmpfile, 17188c2ecf20Sopenharmony_ci}; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ciconst struct file_operations ubifs_dir_operations = { 17218c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 17228c2ecf20Sopenharmony_ci .release = ubifs_dir_release, 17238c2ecf20Sopenharmony_ci .read = generic_read_dir, 17248c2ecf20Sopenharmony_ci .iterate_shared = ubifs_readdir, 17258c2ecf20Sopenharmony_ci .fsync = ubifs_fsync, 17268c2ecf20Sopenharmony_ci .unlocked_ioctl = ubifs_ioctl, 17278c2ecf20Sopenharmony_ci .open = ubifs_dir_open, 17288c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17298c2ecf20Sopenharmony_ci .compat_ioctl = ubifs_compat_ioctl, 17308c2ecf20Sopenharmony_ci#endif 17318c2ecf20Sopenharmony_ci}; 1732