162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* * This file is part of UBIFS. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 562306a36Sopenharmony_ci * Copyright (C) 2006, 2007 University of Szeged, Hungary 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Authors: Artem Bityutskiy (Битюцкий Артём) 862306a36Sopenharmony_ci * Adrian Hunter 962306a36Sopenharmony_ci * Zoltan Sogor 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* 1362306a36Sopenharmony_ci * This file implements directory operations. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * All FS operations in this file allocate budget before writing anything to the 1662306a36Sopenharmony_ci * media. If they fail to allocate it, the error is returned. The only 1762306a36Sopenharmony_ci * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even 1862306a36Sopenharmony_ci * if they unable to allocate the budget, because deletion %-ENOSPC failure is 1962306a36Sopenharmony_ci * not what users are usually ready to get. UBIFS budgeting subsystem has some 2062306a36Sopenharmony_ci * space reserved for these purposes. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * All operations in this file write all inodes which they change straight 2362306a36Sopenharmony_ci * away, instead of marking them dirty. For example, 'ubifs_link()' changes 2462306a36Sopenharmony_ci * @i_size of the parent inode and writes the parent inode together with the 2562306a36Sopenharmony_ci * target inode. This was done to simplify file-system recovery which would 2662306a36Sopenharmony_ci * otherwise be very difficult to do. The only exception is rename which marks 2762306a36Sopenharmony_ci * the re-named inode dirty (because its @i_ctime is updated) but does not 2862306a36Sopenharmony_ci * write it, but just marks it as dirty. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include "ubifs.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/** 3462306a36Sopenharmony_ci * inherit_flags - inherit flags of the parent inode. 3562306a36Sopenharmony_ci * @dir: parent inode 3662306a36Sopenharmony_ci * @mode: new inode mode flags 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * This is a helper function for 'ubifs_new_inode()' which inherits flag of the 3962306a36Sopenharmony_ci * parent directory inode @dir. UBIFS inodes inherit the following flags: 4062306a36Sopenharmony_ci * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on 4162306a36Sopenharmony_ci * sub-directory basis; 4262306a36Sopenharmony_ci * o %UBIFS_SYNC_FL - useful for the same reasons; 4362306a36Sopenharmony_ci * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * This function returns the inherited flags. 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cistatic int inherit_flags(const struct inode *dir, umode_t mode) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci int flags; 5062306a36Sopenharmony_ci const struct ubifs_inode *ui = ubifs_inode(dir); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!S_ISDIR(dir->i_mode)) 5362306a36Sopenharmony_ci /* 5462306a36Sopenharmony_ci * The parent is not a directory, which means that an extended 5562306a36Sopenharmony_ci * attribute inode is being created. No flags. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); 6062306a36Sopenharmony_ci if (!S_ISDIR(mode)) 6162306a36Sopenharmony_ci /* The "DIRSYNC" flag only applies to directories */ 6262306a36Sopenharmony_ci flags &= ~UBIFS_DIRSYNC_FL; 6362306a36Sopenharmony_ci return flags; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * ubifs_new_inode - allocate new UBIFS inode object. 6862306a36Sopenharmony_ci * @c: UBIFS file-system description object 6962306a36Sopenharmony_ci * @dir: parent directory inode 7062306a36Sopenharmony_ci * @mode: inode mode flags 7162306a36Sopenharmony_ci * @is_xattr: whether the inode is xattr inode 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * This function finds an unused inode number, allocates new inode and 7462306a36Sopenharmony_ci * initializes it. Returns new inode in case of success and an error code in 7562306a36Sopenharmony_ci * case of failure. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_cistruct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, 7862306a36Sopenharmony_ci umode_t mode, bool is_xattr) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci int err; 8162306a36Sopenharmony_ci struct inode *inode; 8262306a36Sopenharmony_ci struct ubifs_inode *ui; 8362306a36Sopenharmony_ci bool encrypted = false; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci inode = new_inode(c->vfs_sb); 8662306a36Sopenharmony_ci ui = ubifs_inode(inode); 8762306a36Sopenharmony_ci if (!inode) 8862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci /* 9162306a36Sopenharmony_ci * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and 9262306a36Sopenharmony_ci * marking them dirty in file write path (see 'file_update_time()'). 9362306a36Sopenharmony_ci * UBIFS has to fully control "clean <-> dirty" transitions of inodes 9462306a36Sopenharmony_ci * to make budgeting work. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci inode->i_flags |= S_NOCMTIME; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci inode_init_owner(&nop_mnt_idmap, inode, dir, mode); 9962306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode); 10062306a36Sopenharmony_ci inode->i_mapping->nrpages = 0; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (!is_xattr) { 10362306a36Sopenharmony_ci err = fscrypt_prepare_new_inode(dir, inode, &encrypted); 10462306a36Sopenharmony_ci if (err) { 10562306a36Sopenharmony_ci ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err); 10662306a36Sopenharmony_ci goto out_iput; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci switch (mode & S_IFMT) { 11162306a36Sopenharmony_ci case S_IFREG: 11262306a36Sopenharmony_ci inode->i_mapping->a_ops = &ubifs_file_address_operations; 11362306a36Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 11462306a36Sopenharmony_ci inode->i_fop = &ubifs_file_operations; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci case S_IFDIR: 11762306a36Sopenharmony_ci inode->i_op = &ubifs_dir_inode_operations; 11862306a36Sopenharmony_ci inode->i_fop = &ubifs_dir_operations; 11962306a36Sopenharmony_ci inode->i_size = ui->ui_size = UBIFS_INO_NODE_SZ; 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case S_IFLNK: 12262306a36Sopenharmony_ci inode->i_op = &ubifs_symlink_inode_operations; 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci case S_IFSOCK: 12562306a36Sopenharmony_ci case S_IFIFO: 12662306a36Sopenharmony_ci case S_IFBLK: 12762306a36Sopenharmony_ci case S_IFCHR: 12862306a36Sopenharmony_ci inode->i_op = &ubifs_file_inode_operations; 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci default: 13162306a36Sopenharmony_ci BUG(); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ui->flags = inherit_flags(dir, mode); 13562306a36Sopenharmony_ci ubifs_set_inode_flags(inode); 13662306a36Sopenharmony_ci if (S_ISREG(mode)) 13762306a36Sopenharmony_ci ui->compr_type = c->default_compr; 13862306a36Sopenharmony_ci else 13962306a36Sopenharmony_ci ui->compr_type = UBIFS_COMPR_NONE; 14062306a36Sopenharmony_ci ui->synced_i_size = 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci spin_lock(&c->cnt_lock); 14362306a36Sopenharmony_ci /* Inode number overflow is currently not supported */ 14462306a36Sopenharmony_ci if (c->highest_inum >= INUM_WARN_WATERMARK) { 14562306a36Sopenharmony_ci if (c->highest_inum >= INUM_WATERMARK) { 14662306a36Sopenharmony_ci spin_unlock(&c->cnt_lock); 14762306a36Sopenharmony_ci ubifs_err(c, "out of inode numbers"); 14862306a36Sopenharmony_ci err = -EINVAL; 14962306a36Sopenharmony_ci goto out_iput; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci ubifs_warn(c, "running out of inode numbers (current %lu, max %u)", 15262306a36Sopenharmony_ci (unsigned long)c->highest_inum, INUM_WATERMARK); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci inode->i_ino = ++c->highest_inum; 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * The creation sequence number remains with this inode for its 15862306a36Sopenharmony_ci * lifetime. All nodes for this inode have a greater sequence number, 15962306a36Sopenharmony_ci * and so it is possible to distinguish obsolete nodes belonging to a 16062306a36Sopenharmony_ci * previous incarnation of the same inode number - for example, for the 16162306a36Sopenharmony_ci * purpose of rebuilding the index. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci ui->creat_sqnum = ++c->max_sqnum; 16462306a36Sopenharmony_ci spin_unlock(&c->cnt_lock); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (encrypted) { 16762306a36Sopenharmony_ci err = fscrypt_set_context(inode, NULL); 16862306a36Sopenharmony_ci if (err) { 16962306a36Sopenharmony_ci ubifs_err(c, "fscrypt_set_context failed: %i", err); 17062306a36Sopenharmony_ci goto out_iput; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return inode; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ciout_iput: 17762306a36Sopenharmony_ci make_bad_inode(inode); 17862306a36Sopenharmony_ci iput(inode); 17962306a36Sopenharmony_ci return ERR_PTR(err); 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int dbg_check_name(const struct ubifs_info *c, 18362306a36Sopenharmony_ci const struct ubifs_dent_node *dent, 18462306a36Sopenharmony_ci const struct fscrypt_name *nm) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci if (!dbg_is_chk_gen(c)) 18762306a36Sopenharmony_ci return 0; 18862306a36Sopenharmony_ci if (le16_to_cpu(dent->nlen) != fname_len(nm)) 18962306a36Sopenharmony_ci return -EINVAL; 19062306a36Sopenharmony_ci if (memcmp(dent->name, fname_name(nm), fname_len(nm))) 19162306a36Sopenharmony_ci return -EINVAL; 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, 19662306a36Sopenharmony_ci unsigned int flags) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci int err; 19962306a36Sopenharmony_ci union ubifs_key key; 20062306a36Sopenharmony_ci struct inode *inode = NULL; 20162306a36Sopenharmony_ci struct ubifs_dent_node *dent = NULL; 20262306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 20362306a36Sopenharmony_ci struct fscrypt_name nm; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci err = fscrypt_prepare_lookup(dir, dentry, &nm); 20862306a36Sopenharmony_ci generic_set_encrypted_ci_d_ops(dentry); 20962306a36Sopenharmony_ci if (err == -ENOENT) 21062306a36Sopenharmony_ci return d_splice_alias(NULL, dentry); 21162306a36Sopenharmony_ci if (err) 21262306a36Sopenharmony_ci return ERR_PTR(err); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (fname_len(&nm) > UBIFS_MAX_NLEN) { 21562306a36Sopenharmony_ci inode = ERR_PTR(-ENAMETOOLONG); 21662306a36Sopenharmony_ci goto done; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); 22062306a36Sopenharmony_ci if (!dent) { 22162306a36Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 22262306a36Sopenharmony_ci goto done; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (fname_name(&nm) == NULL) { 22662306a36Sopenharmony_ci if (nm.hash & ~UBIFS_S_KEY_HASH_MASK) 22762306a36Sopenharmony_ci goto done; /* ENOENT */ 22862306a36Sopenharmony_ci dent_key_init_hash(c, &key, dir->i_ino, nm.hash); 22962306a36Sopenharmony_ci err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash); 23062306a36Sopenharmony_ci } else { 23162306a36Sopenharmony_ci dent_key_init(c, &key, dir->i_ino, &nm); 23262306a36Sopenharmony_ci err = ubifs_tnc_lookup_nm(c, &key, dent, &nm); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci if (err) { 23662306a36Sopenharmony_ci if (err == -ENOENT) 23762306a36Sopenharmony_ci dbg_gen("not found"); 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci inode = ERR_PTR(err); 24062306a36Sopenharmony_ci goto done; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (dbg_check_name(c, dent, &nm)) { 24462306a36Sopenharmony_ci inode = ERR_PTR(-EINVAL); 24562306a36Sopenharmony_ci goto done; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); 24962306a36Sopenharmony_ci if (IS_ERR(inode)) { 25062306a36Sopenharmony_ci /* 25162306a36Sopenharmony_ci * This should not happen. Probably the file-system needs 25262306a36Sopenharmony_ci * checking. 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_ci err = PTR_ERR(inode); 25562306a36Sopenharmony_ci ubifs_err(c, "dead directory entry '%pd', error %d", 25662306a36Sopenharmony_ci dentry, err); 25762306a36Sopenharmony_ci ubifs_ro_mode(c, err); 25862306a36Sopenharmony_ci goto done; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (IS_ENCRYPTED(dir) && 26262306a36Sopenharmony_ci (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && 26362306a36Sopenharmony_ci !fscrypt_has_permitted_context(dir, inode)) { 26462306a36Sopenharmony_ci ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu", 26562306a36Sopenharmony_ci dir->i_ino, inode->i_ino); 26662306a36Sopenharmony_ci iput(inode); 26762306a36Sopenharmony_ci inode = ERR_PTR(-EPERM); 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cidone: 27162306a36Sopenharmony_ci kfree(dent); 27262306a36Sopenharmony_ci fscrypt_free_filename(&nm); 27362306a36Sopenharmony_ci return d_splice_alias(inode, dentry); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int ubifs_prepare_create(struct inode *dir, struct dentry *dentry, 27762306a36Sopenharmony_ci struct fscrypt_name *nm) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci if (fscrypt_is_nokey_name(dentry)) 28062306a36Sopenharmony_ci return -ENOKEY; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return fscrypt_setup_filename(dir, &dentry->d_name, 0, nm); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int ubifs_create(struct mnt_idmap *idmap, struct inode *dir, 28662306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, bool excl) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct inode *inode; 28962306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 29062306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 29162306a36Sopenharmony_ci .dirtied_ino = 1 }; 29262306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 29362306a36Sopenharmony_ci struct fscrypt_name nm; 29462306a36Sopenharmony_ci int err, sz_change; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * Budget request settings: new inode, new direntry, changing the 29862306a36Sopenharmony_ci * parent directory inode. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 30262306a36Sopenharmony_ci dentry, mode, dir->i_ino); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 30562306a36Sopenharmony_ci if (err) 30662306a36Sopenharmony_ci return err; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 30962306a36Sopenharmony_ci if (err) 31062306a36Sopenharmony_ci goto out_budg; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode, false); 31562306a36Sopenharmony_ci if (IS_ERR(inode)) { 31662306a36Sopenharmony_ci err = PTR_ERR(inode); 31762306a36Sopenharmony_ci goto out_fname; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 32162306a36Sopenharmony_ci if (err) 32262306a36Sopenharmony_ci goto out_inode; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 32562306a36Sopenharmony_ci dir->i_size += sz_change; 32662306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 32762306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 32862306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 32962306a36Sopenharmony_ci if (err) 33062306a36Sopenharmony_ci goto out_cancel; 33162306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ubifs_release_budget(c, &req); 33462306a36Sopenharmony_ci fscrypt_free_filename(&nm); 33562306a36Sopenharmony_ci insert_inode_hash(inode); 33662306a36Sopenharmony_ci d_instantiate(dentry, inode); 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ciout_cancel: 34062306a36Sopenharmony_ci dir->i_size -= sz_change; 34162306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 34262306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 34362306a36Sopenharmony_ciout_inode: 34462306a36Sopenharmony_ci make_bad_inode(inode); 34562306a36Sopenharmony_ci iput(inode); 34662306a36Sopenharmony_ciout_fname: 34762306a36Sopenharmony_ci fscrypt_free_filename(&nm); 34862306a36Sopenharmony_ciout_budg: 34962306a36Sopenharmony_ci ubifs_release_budget(c, &req); 35062306a36Sopenharmony_ci ubifs_err(c, "cannot create regular file, error %d", err); 35162306a36Sopenharmony_ci return err; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic struct inode *create_whiteout(struct inode *dir, struct dentry *dentry) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci int err; 35762306a36Sopenharmony_ci umode_t mode = S_IFCHR | WHITEOUT_MODE; 35862306a36Sopenharmony_ci struct inode *inode; 35962306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* 36262306a36Sopenharmony_ci * Create an inode('nlink = 1') for whiteout without updating journal, 36362306a36Sopenharmony_ci * let ubifs_jnl_rename() store it on flash to complete rename whiteout 36462306a36Sopenharmony_ci * atomically. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 36862306a36Sopenharmony_ci dentry, mode, dir->i_ino); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode, false); 37162306a36Sopenharmony_ci if (IS_ERR(inode)) { 37262306a36Sopenharmony_ci err = PTR_ERR(inode); 37362306a36Sopenharmony_ci goto out_free; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, WHITEOUT_DEV); 37762306a36Sopenharmony_ci ubifs_assert(c, inode->i_op == &ubifs_file_inode_operations); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 38062306a36Sopenharmony_ci if (err) 38162306a36Sopenharmony_ci goto out_inode; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* The dir size is updated by do_rename. */ 38462306a36Sopenharmony_ci insert_inode_hash(inode); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return inode; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ciout_inode: 38962306a36Sopenharmony_ci make_bad_inode(inode); 39062306a36Sopenharmony_ci iput(inode); 39162306a36Sopenharmony_ciout_free: 39262306a36Sopenharmony_ci ubifs_err(c, "cannot create whiteout file, error %d", err); 39362306a36Sopenharmony_ci return ERR_PTR(err); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/** 39762306a36Sopenharmony_ci * lock_2_inodes - a wrapper for locking two UBIFS inodes. 39862306a36Sopenharmony_ci * @inode1: first inode 39962306a36Sopenharmony_ci * @inode2: second inode 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * We do not implement any tricks to guarantee strict lock ordering, because 40262306a36Sopenharmony_ci * VFS has already done it for us on the @i_mutex. So this is just a simple 40362306a36Sopenharmony_ci * wrapper function. 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_cistatic void lock_2_inodes(struct inode *inode1, struct inode *inode2) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); 40862306a36Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/** 41262306a36Sopenharmony_ci * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. 41362306a36Sopenharmony_ci * @inode1: first inode 41462306a36Sopenharmony_ci * @inode2: second inode 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_cistatic void unlock_2_inodes(struct inode *inode1, struct inode *inode2) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci mutex_unlock(&ubifs_inode(inode2)->ui_mutex); 41962306a36Sopenharmony_ci mutex_unlock(&ubifs_inode(inode1)->ui_mutex); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int ubifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, 42362306a36Sopenharmony_ci struct file *file, umode_t mode) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct dentry *dentry = file->f_path.dentry; 42662306a36Sopenharmony_ci struct inode *inode; 42762306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 42862306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 42962306a36Sopenharmony_ci .dirtied_ino = 1}; 43062306a36Sopenharmony_ci struct ubifs_budget_req ino_req = { .dirtied_ino = 1 }; 43162306a36Sopenharmony_ci struct ubifs_inode *ui; 43262306a36Sopenharmony_ci int err, instantiated = 0; 43362306a36Sopenharmony_ci struct fscrypt_name nm; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* 43662306a36Sopenharmony_ci * Budget request settings: new inode, new direntry, changing the 43762306a36Sopenharmony_ci * parent directory inode. 43862306a36Sopenharmony_ci * Allocate budget separately for new dirtied inode, the budget will 43962306a36Sopenharmony_ci * be released via writeback. 44062306a36Sopenharmony_ci */ 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 44362306a36Sopenharmony_ci dentry, mode, dir->i_ino); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); 44662306a36Sopenharmony_ci if (err) 44762306a36Sopenharmony_ci return err; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 45062306a36Sopenharmony_ci if (err) { 45162306a36Sopenharmony_ci fscrypt_free_filename(&nm); 45262306a36Sopenharmony_ci return err; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci err = ubifs_budget_space(c, &ino_req); 45662306a36Sopenharmony_ci if (err) { 45762306a36Sopenharmony_ci ubifs_release_budget(c, &req); 45862306a36Sopenharmony_ci fscrypt_free_filename(&nm); 45962306a36Sopenharmony_ci return err; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode, false); 46362306a36Sopenharmony_ci if (IS_ERR(inode)) { 46462306a36Sopenharmony_ci err = PTR_ERR(inode); 46562306a36Sopenharmony_ci goto out_budg; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci ui = ubifs_inode(inode); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 47062306a36Sopenharmony_ci if (err) 47162306a36Sopenharmony_ci goto out_inode; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci mutex_lock(&ui->ui_mutex); 47462306a36Sopenharmony_ci insert_inode_hash(inode); 47562306a36Sopenharmony_ci d_tmpfile(file, inode); 47662306a36Sopenharmony_ci ubifs_assert(c, ui->dirty); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci instantiated = 1; 47962306a36Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci lock_2_inodes(dir, inode); 48262306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); 48362306a36Sopenharmony_ci if (err) 48462306a36Sopenharmony_ci goto out_cancel; 48562306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ubifs_release_budget(c, &req); 48862306a36Sopenharmony_ci fscrypt_free_filename(&nm); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return finish_open_simple(file, 0); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ciout_cancel: 49362306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 49462306a36Sopenharmony_ciout_inode: 49562306a36Sopenharmony_ci make_bad_inode(inode); 49662306a36Sopenharmony_ci if (!instantiated) 49762306a36Sopenharmony_ci iput(inode); 49862306a36Sopenharmony_ciout_budg: 49962306a36Sopenharmony_ci ubifs_release_budget(c, &req); 50062306a36Sopenharmony_ci if (!instantiated) 50162306a36Sopenharmony_ci ubifs_release_budget(c, &ino_req); 50262306a36Sopenharmony_ci fscrypt_free_filename(&nm); 50362306a36Sopenharmony_ci ubifs_err(c, "cannot create temporary file, error %d", err); 50462306a36Sopenharmony_ci return err; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci/** 50862306a36Sopenharmony_ci * vfs_dent_type - get VFS directory entry type. 50962306a36Sopenharmony_ci * @type: UBIFS directory entry type 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * This function converts UBIFS directory entry type into VFS directory entry 51262306a36Sopenharmony_ci * type. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_cistatic unsigned int vfs_dent_type(uint8_t type) 51562306a36Sopenharmony_ci{ 51662306a36Sopenharmony_ci switch (type) { 51762306a36Sopenharmony_ci case UBIFS_ITYPE_REG: 51862306a36Sopenharmony_ci return DT_REG; 51962306a36Sopenharmony_ci case UBIFS_ITYPE_DIR: 52062306a36Sopenharmony_ci return DT_DIR; 52162306a36Sopenharmony_ci case UBIFS_ITYPE_LNK: 52262306a36Sopenharmony_ci return DT_LNK; 52362306a36Sopenharmony_ci case UBIFS_ITYPE_BLK: 52462306a36Sopenharmony_ci return DT_BLK; 52562306a36Sopenharmony_ci case UBIFS_ITYPE_CHR: 52662306a36Sopenharmony_ci return DT_CHR; 52762306a36Sopenharmony_ci case UBIFS_ITYPE_FIFO: 52862306a36Sopenharmony_ci return DT_FIFO; 52962306a36Sopenharmony_ci case UBIFS_ITYPE_SOCK: 53062306a36Sopenharmony_ci return DT_SOCK; 53162306a36Sopenharmony_ci default: 53262306a36Sopenharmony_ci BUG(); 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/* 53862306a36Sopenharmony_ci * The classical Unix view for directory is that it is a linear array of 53962306a36Sopenharmony_ci * (name, inode number) entries. Linux/VFS assumes this model as well. 54062306a36Sopenharmony_ci * Particularly, 'readdir()' call wants us to return a directory entry offset 54162306a36Sopenharmony_ci * which later may be used to continue 'readdir()'ing the directory or to 54262306a36Sopenharmony_ci * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this 54362306a36Sopenharmony_ci * model because directory entries are identified by keys, which may collide. 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * UBIFS uses directory entry hash value for directory offsets, so 54662306a36Sopenharmony_ci * 'seekdir()'/'telldir()' may not always work because of possible key 54762306a36Sopenharmony_ci * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work 54862306a36Sopenharmony_ci * properly by means of saving full directory entry name in the private field 54962306a36Sopenharmony_ci * of the file description object. 55062306a36Sopenharmony_ci * 55162306a36Sopenharmony_ci * This means that UBIFS cannot support NFS which requires full 55262306a36Sopenharmony_ci * 'seekdir()'/'telldir()' support. 55362306a36Sopenharmony_ci */ 55462306a36Sopenharmony_cistatic int ubifs_readdir(struct file *file, struct dir_context *ctx) 55562306a36Sopenharmony_ci{ 55662306a36Sopenharmony_ci int fstr_real_len = 0, err = 0; 55762306a36Sopenharmony_ci struct fscrypt_name nm; 55862306a36Sopenharmony_ci struct fscrypt_str fstr = {0}; 55962306a36Sopenharmony_ci union ubifs_key key; 56062306a36Sopenharmony_ci struct ubifs_dent_node *dent; 56162306a36Sopenharmony_ci struct inode *dir = file_inode(file); 56262306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 56362306a36Sopenharmony_ci bool encrypted = IS_ENCRYPTED(dir); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2) 56862306a36Sopenharmony_ci /* 56962306a36Sopenharmony_ci * The directory was seek'ed to a senseless position or there 57062306a36Sopenharmony_ci * are no more entries. 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_ci return 0; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (encrypted) { 57562306a36Sopenharmony_ci err = fscrypt_prepare_readdir(dir); 57662306a36Sopenharmony_ci if (err) 57762306a36Sopenharmony_ci return err; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci err = fscrypt_fname_alloc_buffer(UBIFS_MAX_NLEN, &fstr); 58062306a36Sopenharmony_ci if (err) 58162306a36Sopenharmony_ci return err; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci fstr_real_len = fstr.len; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (file->f_version == 0) { 58762306a36Sopenharmony_ci /* 58862306a36Sopenharmony_ci * The file was seek'ed, which means that @file->private_data 58962306a36Sopenharmony_ci * is now invalid. This may also be just the first 59062306a36Sopenharmony_ci * 'ubifs_readdir()' invocation, in which case 59162306a36Sopenharmony_ci * @file->private_data is NULL, and the below code is 59262306a36Sopenharmony_ci * basically a no-op. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci kfree(file->private_data); 59562306a36Sopenharmony_ci file->private_data = NULL; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * 'generic_file_llseek()' unconditionally sets @file->f_version to 60062306a36Sopenharmony_ci * zero, and we use this for detecting whether the file was seek'ed. 60162306a36Sopenharmony_ci */ 60262306a36Sopenharmony_ci file->f_version = 1; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* File positions 0 and 1 correspond to "." and ".." */ 60562306a36Sopenharmony_ci if (ctx->pos < 2) { 60662306a36Sopenharmony_ci ubifs_assert(c, !file->private_data); 60762306a36Sopenharmony_ci if (!dir_emit_dots(file, ctx)) { 60862306a36Sopenharmony_ci if (encrypted) 60962306a36Sopenharmony_ci fscrypt_fname_free_buffer(&fstr); 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* Find the first entry in TNC and save it */ 61462306a36Sopenharmony_ci lowest_dent_key(c, &key, dir->i_ino); 61562306a36Sopenharmony_ci fname_len(&nm) = 0; 61662306a36Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 61762306a36Sopenharmony_ci if (IS_ERR(dent)) { 61862306a36Sopenharmony_ci err = PTR_ERR(dent); 61962306a36Sopenharmony_ci goto out; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ctx->pos = key_hash_flash(c, &dent->key); 62362306a36Sopenharmony_ci file->private_data = dent; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci dent = file->private_data; 62762306a36Sopenharmony_ci if (!dent) { 62862306a36Sopenharmony_ci /* 62962306a36Sopenharmony_ci * The directory was seek'ed to and is now readdir'ed. 63062306a36Sopenharmony_ci * Find the entry corresponding to @ctx->pos or the closest one. 63162306a36Sopenharmony_ci */ 63262306a36Sopenharmony_ci dent_key_init_hash(c, &key, dir->i_ino, ctx->pos); 63362306a36Sopenharmony_ci fname_len(&nm) = 0; 63462306a36Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 63562306a36Sopenharmony_ci if (IS_ERR(dent)) { 63662306a36Sopenharmony_ci err = PTR_ERR(dent); 63762306a36Sopenharmony_ci goto out; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci ctx->pos = key_hash_flash(c, &dent->key); 64062306a36Sopenharmony_ci file->private_data = dent; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci while (1) { 64462306a36Sopenharmony_ci dbg_gen("ino %llu, new f_pos %#x", 64562306a36Sopenharmony_ci (unsigned long long)le64_to_cpu(dent->inum), 64662306a36Sopenharmony_ci key_hash_flash(c, &dent->key)); 64762306a36Sopenharmony_ci ubifs_assert(c, le64_to_cpu(dent->ch.sqnum) > 64862306a36Sopenharmony_ci ubifs_inode(dir)->creat_sqnum); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci fname_len(&nm) = le16_to_cpu(dent->nlen); 65162306a36Sopenharmony_ci fname_name(&nm) = dent->name; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci if (encrypted) { 65462306a36Sopenharmony_ci fstr.len = fstr_real_len; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c, 65762306a36Sopenharmony_ci &dent->key), 65862306a36Sopenharmony_ci le32_to_cpu(dent->cookie), 65962306a36Sopenharmony_ci &nm.disk_name, &fstr); 66062306a36Sopenharmony_ci if (err) 66162306a36Sopenharmony_ci goto out; 66262306a36Sopenharmony_ci } else { 66362306a36Sopenharmony_ci fstr.len = fname_len(&nm); 66462306a36Sopenharmony_ci fstr.name = fname_name(&nm); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (!dir_emit(ctx, fstr.name, fstr.len, 66862306a36Sopenharmony_ci le64_to_cpu(dent->inum), 66962306a36Sopenharmony_ci vfs_dent_type(dent->type))) { 67062306a36Sopenharmony_ci if (encrypted) 67162306a36Sopenharmony_ci fscrypt_fname_free_buffer(&fstr); 67262306a36Sopenharmony_ci return 0; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Switch to the next entry */ 67662306a36Sopenharmony_ci key_read(c, &dent->key, &key); 67762306a36Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 67862306a36Sopenharmony_ci if (IS_ERR(dent)) { 67962306a36Sopenharmony_ci err = PTR_ERR(dent); 68062306a36Sopenharmony_ci goto out; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci kfree(file->private_data); 68462306a36Sopenharmony_ci ctx->pos = key_hash_flash(c, &dent->key); 68562306a36Sopenharmony_ci file->private_data = dent; 68662306a36Sopenharmony_ci cond_resched(); 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ciout: 69062306a36Sopenharmony_ci kfree(file->private_data); 69162306a36Sopenharmony_ci file->private_data = NULL; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci if (encrypted) 69462306a36Sopenharmony_ci fscrypt_fname_free_buffer(&fstr); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (err != -ENOENT) 69762306a36Sopenharmony_ci ubifs_err(c, "cannot find next direntry, error %d", err); 69862306a36Sopenharmony_ci else 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * -ENOENT is a non-fatal error in this context, the TNC uses 70162306a36Sopenharmony_ci * it to indicate that the cursor moved past the current directory 70262306a36Sopenharmony_ci * and readdir() has to stop. 70362306a36Sopenharmony_ci */ 70462306a36Sopenharmony_ci err = 0; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* 2 is a special value indicating that there are no more direntries */ 70862306a36Sopenharmony_ci ctx->pos = 2; 70962306a36Sopenharmony_ci return err; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/* Free saved readdir() state when the directory is closed */ 71362306a36Sopenharmony_cistatic int ubifs_dir_release(struct inode *dir, struct file *file) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci kfree(file->private_data); 71662306a36Sopenharmony_ci file->private_data = NULL; 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int ubifs_link(struct dentry *old_dentry, struct inode *dir, 72162306a36Sopenharmony_ci struct dentry *dentry) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 72462306a36Sopenharmony_ci struct inode *inode = d_inode(old_dentry); 72562306a36Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 72662306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 72762306a36Sopenharmony_ci int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); 72862306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, 72962306a36Sopenharmony_ci .dirtied_ino_d = ALIGN(ui->data_len, 8) }; 73062306a36Sopenharmony_ci struct fscrypt_name nm; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci /* 73362306a36Sopenharmony_ci * Budget request settings: new direntry, changing the target inode, 73462306a36Sopenharmony_ci * changing the parent inode. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci dbg_gen("dent '%pd' to ino %lu (nlink %d) in dir ino %lu", 73862306a36Sopenharmony_ci dentry, inode->i_ino, 73962306a36Sopenharmony_ci inode->i_nlink, dir->i_ino); 74062306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(dir)); 74162306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(inode)); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci err = fscrypt_prepare_link(old_dentry, dir, dentry); 74462306a36Sopenharmony_ci if (err) 74562306a36Sopenharmony_ci return err; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); 74862306a36Sopenharmony_ci if (err) 74962306a36Sopenharmony_ci return err; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci err = dbg_check_synced_i_size(c, inode); 75262306a36Sopenharmony_ci if (err) 75362306a36Sopenharmony_ci goto out_fname; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 75662306a36Sopenharmony_ci if (err) 75762306a36Sopenharmony_ci goto out_fname; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci lock_2_inodes(dir, inode); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */ 76262306a36Sopenharmony_ci if (inode->i_nlink == 0) 76362306a36Sopenharmony_ci ubifs_delete_orphan(c, inode->i_ino); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci inc_nlink(inode); 76662306a36Sopenharmony_ci ihold(inode); 76762306a36Sopenharmony_ci inode_set_ctime_current(inode); 76862306a36Sopenharmony_ci dir->i_size += sz_change; 76962306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 77062306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 77162306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 77262306a36Sopenharmony_ci if (err) 77362306a36Sopenharmony_ci goto out_cancel; 77462306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci ubifs_release_budget(c, &req); 77762306a36Sopenharmony_ci d_instantiate(dentry, inode); 77862306a36Sopenharmony_ci fscrypt_free_filename(&nm); 77962306a36Sopenharmony_ci return 0; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ciout_cancel: 78262306a36Sopenharmony_ci dir->i_size -= sz_change; 78362306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 78462306a36Sopenharmony_ci drop_nlink(inode); 78562306a36Sopenharmony_ci if (inode->i_nlink == 0) 78662306a36Sopenharmony_ci ubifs_add_orphan(c, inode->i_ino); 78762306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 78862306a36Sopenharmony_ci ubifs_release_budget(c, &req); 78962306a36Sopenharmony_ci iput(inode); 79062306a36Sopenharmony_ciout_fname: 79162306a36Sopenharmony_ci fscrypt_free_filename(&nm); 79262306a36Sopenharmony_ci return err; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic int ubifs_unlink(struct inode *dir, struct dentry *dentry) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 79862306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 79962306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 80062306a36Sopenharmony_ci int err, sz_change, budgeted = 1; 80162306a36Sopenharmony_ci struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; 80262306a36Sopenharmony_ci unsigned int saved_nlink = inode->i_nlink; 80362306a36Sopenharmony_ci struct fscrypt_name nm; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci /* 80662306a36Sopenharmony_ci * Budget request settings: deletion direntry, deletion inode (+1 for 80762306a36Sopenharmony_ci * @dirtied_ino), changing the parent directory inode. If budgeting 80862306a36Sopenharmony_ci * fails, go ahead anyway because we have extra space reserved for 80962306a36Sopenharmony_ci * deletions. 81062306a36Sopenharmony_ci */ 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu", 81362306a36Sopenharmony_ci dentry, inode->i_ino, 81462306a36Sopenharmony_ci inode->i_nlink, dir->i_ino); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); 81762306a36Sopenharmony_ci if (err) 81862306a36Sopenharmony_ci return err; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci err = ubifs_purge_xattrs(inode); 82162306a36Sopenharmony_ci if (err) 82262306a36Sopenharmony_ci return err; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(dir)); 82762306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(inode)); 82862306a36Sopenharmony_ci err = dbg_check_synced_i_size(c, inode); 82962306a36Sopenharmony_ci if (err) 83062306a36Sopenharmony_ci goto out_fname; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 83362306a36Sopenharmony_ci if (err) { 83462306a36Sopenharmony_ci if (err != -ENOSPC) 83562306a36Sopenharmony_ci goto out_fname; 83662306a36Sopenharmony_ci budgeted = 0; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci lock_2_inodes(dir, inode); 84062306a36Sopenharmony_ci inode_set_ctime_current(inode); 84162306a36Sopenharmony_ci drop_nlink(inode); 84262306a36Sopenharmony_ci dir->i_size -= sz_change; 84362306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 84462306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 84562306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); 84662306a36Sopenharmony_ci if (err) 84762306a36Sopenharmony_ci goto out_cancel; 84862306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (budgeted) 85162306a36Sopenharmony_ci ubifs_release_budget(c, &req); 85262306a36Sopenharmony_ci else { 85362306a36Sopenharmony_ci /* We've deleted something - clean the "no space" flags */ 85462306a36Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 85562306a36Sopenharmony_ci smp_wmb(); 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci fscrypt_free_filename(&nm); 85862306a36Sopenharmony_ci return 0; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ciout_cancel: 86162306a36Sopenharmony_ci dir->i_size += sz_change; 86262306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 86362306a36Sopenharmony_ci set_nlink(inode, saved_nlink); 86462306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 86562306a36Sopenharmony_ci if (budgeted) 86662306a36Sopenharmony_ci ubifs_release_budget(c, &req); 86762306a36Sopenharmony_ciout_fname: 86862306a36Sopenharmony_ci fscrypt_free_filename(&nm); 86962306a36Sopenharmony_ci return err; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci/** 87362306a36Sopenharmony_ci * ubifs_check_dir_empty - check if a directory is empty or not. 87462306a36Sopenharmony_ci * @dir: VFS inode object of the directory to check 87562306a36Sopenharmony_ci * 87662306a36Sopenharmony_ci * This function checks if directory @dir is empty. Returns zero if the 87762306a36Sopenharmony_ci * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes 87862306a36Sopenharmony_ci * in case of errors. 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_ciint ubifs_check_dir_empty(struct inode *dir) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 88362306a36Sopenharmony_ci struct fscrypt_name nm = { 0 }; 88462306a36Sopenharmony_ci struct ubifs_dent_node *dent; 88562306a36Sopenharmony_ci union ubifs_key key; 88662306a36Sopenharmony_ci int err; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci lowest_dent_key(c, &key, dir->i_ino); 88962306a36Sopenharmony_ci dent = ubifs_tnc_next_ent(c, &key, &nm); 89062306a36Sopenharmony_ci if (IS_ERR(dent)) { 89162306a36Sopenharmony_ci err = PTR_ERR(dent); 89262306a36Sopenharmony_ci if (err == -ENOENT) 89362306a36Sopenharmony_ci err = 0; 89462306a36Sopenharmony_ci } else { 89562306a36Sopenharmony_ci kfree(dent); 89662306a36Sopenharmony_ci err = -ENOTEMPTY; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci return err; 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_cistatic int ubifs_rmdir(struct inode *dir, struct dentry *dentry) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 90462306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 90562306a36Sopenharmony_ci int err, sz_change, budgeted = 1; 90662306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 90762306a36Sopenharmony_ci struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; 90862306a36Sopenharmony_ci struct fscrypt_name nm; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* 91162306a36Sopenharmony_ci * Budget request settings: deletion direntry, deletion inode and 91262306a36Sopenharmony_ci * changing the parent inode. If budgeting fails, go ahead anyway 91362306a36Sopenharmony_ci * because we have extra space reserved for deletions. 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci dbg_gen("directory '%pd', ino %lu in dir ino %lu", dentry, 91762306a36Sopenharmony_ci inode->i_ino, dir->i_ino); 91862306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(dir)); 91962306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(inode)); 92062306a36Sopenharmony_ci err = ubifs_check_dir_empty(d_inode(dentry)); 92162306a36Sopenharmony_ci if (err) 92262306a36Sopenharmony_ci return err; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); 92562306a36Sopenharmony_ci if (err) 92662306a36Sopenharmony_ci return err; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci err = ubifs_purge_xattrs(inode); 92962306a36Sopenharmony_ci if (err) 93062306a36Sopenharmony_ci return err; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 93562306a36Sopenharmony_ci if (err) { 93662306a36Sopenharmony_ci if (err != -ENOSPC) 93762306a36Sopenharmony_ci goto out_fname; 93862306a36Sopenharmony_ci budgeted = 0; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci lock_2_inodes(dir, inode); 94262306a36Sopenharmony_ci inode_set_ctime_current(inode); 94362306a36Sopenharmony_ci clear_nlink(inode); 94462306a36Sopenharmony_ci drop_nlink(dir); 94562306a36Sopenharmony_ci dir->i_size -= sz_change; 94662306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 94762306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 94862306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); 94962306a36Sopenharmony_ci if (err) 95062306a36Sopenharmony_ci goto out_cancel; 95162306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (budgeted) 95462306a36Sopenharmony_ci ubifs_release_budget(c, &req); 95562306a36Sopenharmony_ci else { 95662306a36Sopenharmony_ci /* We've deleted something - clean the "no space" flags */ 95762306a36Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 95862306a36Sopenharmony_ci smp_wmb(); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci fscrypt_free_filename(&nm); 96162306a36Sopenharmony_ci return 0; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ciout_cancel: 96462306a36Sopenharmony_ci dir->i_size += sz_change; 96562306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 96662306a36Sopenharmony_ci inc_nlink(dir); 96762306a36Sopenharmony_ci set_nlink(inode, 2); 96862306a36Sopenharmony_ci unlock_2_inodes(dir, inode); 96962306a36Sopenharmony_ci if (budgeted) 97062306a36Sopenharmony_ci ubifs_release_budget(c, &req); 97162306a36Sopenharmony_ciout_fname: 97262306a36Sopenharmony_ci fscrypt_free_filename(&nm); 97362306a36Sopenharmony_ci return err; 97462306a36Sopenharmony_ci} 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_cistatic int ubifs_mkdir(struct mnt_idmap *idmap, struct inode *dir, 97762306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci struct inode *inode; 98062306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 98162306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 98262306a36Sopenharmony_ci int err, sz_change; 98362306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 98462306a36Sopenharmony_ci .dirtied_ino = 1}; 98562306a36Sopenharmony_ci struct fscrypt_name nm; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci /* 98862306a36Sopenharmony_ci * Budget request settings: new inode, new direntry and changing parent 98962306a36Sopenharmony_ci * directory inode. 99062306a36Sopenharmony_ci */ 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci dbg_gen("dent '%pd', mode %#hx in dir ino %lu", 99362306a36Sopenharmony_ci dentry, mode, dir->i_ino); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 99662306a36Sopenharmony_ci if (err) 99762306a36Sopenharmony_ci return err; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 100062306a36Sopenharmony_ci if (err) 100162306a36Sopenharmony_ci goto out_budg; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci inode = ubifs_new_inode(c, dir, S_IFDIR | mode, false); 100662306a36Sopenharmony_ci if (IS_ERR(inode)) { 100762306a36Sopenharmony_ci err = PTR_ERR(inode); 100862306a36Sopenharmony_ci goto out_fname; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 101262306a36Sopenharmony_ci if (err) 101362306a36Sopenharmony_ci goto out_inode; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 101662306a36Sopenharmony_ci insert_inode_hash(inode); 101762306a36Sopenharmony_ci inc_nlink(inode); 101862306a36Sopenharmony_ci inc_nlink(dir); 101962306a36Sopenharmony_ci dir->i_size += sz_change; 102062306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 102162306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 102262306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 102362306a36Sopenharmony_ci if (err) { 102462306a36Sopenharmony_ci ubifs_err(c, "cannot create directory, error %d", err); 102562306a36Sopenharmony_ci goto out_cancel; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci ubifs_release_budget(c, &req); 103062306a36Sopenharmony_ci d_instantiate(dentry, inode); 103162306a36Sopenharmony_ci fscrypt_free_filename(&nm); 103262306a36Sopenharmony_ci return 0; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ciout_cancel: 103562306a36Sopenharmony_ci dir->i_size -= sz_change; 103662306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 103762306a36Sopenharmony_ci drop_nlink(dir); 103862306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 103962306a36Sopenharmony_ciout_inode: 104062306a36Sopenharmony_ci make_bad_inode(inode); 104162306a36Sopenharmony_ci iput(inode); 104262306a36Sopenharmony_ciout_fname: 104362306a36Sopenharmony_ci fscrypt_free_filename(&nm); 104462306a36Sopenharmony_ciout_budg: 104562306a36Sopenharmony_ci ubifs_release_budget(c, &req); 104662306a36Sopenharmony_ci return err; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic int ubifs_mknod(struct mnt_idmap *idmap, struct inode *dir, 105062306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, dev_t rdev) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct inode *inode; 105362306a36Sopenharmony_ci struct ubifs_inode *ui; 105462306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 105562306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 105662306a36Sopenharmony_ci union ubifs_dev_desc *dev = NULL; 105762306a36Sopenharmony_ci int sz_change; 105862306a36Sopenharmony_ci int err, devlen = 0; 105962306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 106062306a36Sopenharmony_ci .dirtied_ino = 1 }; 106162306a36Sopenharmony_ci struct fscrypt_name nm; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* 106462306a36Sopenharmony_ci * Budget request settings: new inode, new direntry and changing parent 106562306a36Sopenharmony_ci * directory inode. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (S_ISBLK(mode) || S_ISCHR(mode)) { 107162306a36Sopenharmony_ci dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); 107262306a36Sopenharmony_ci if (!dev) 107362306a36Sopenharmony_ci return -ENOMEM; 107462306a36Sopenharmony_ci devlen = ubifs_encode_dev(dev, rdev); 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci req.new_ino_d = ALIGN(devlen, 8); 107862306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 107962306a36Sopenharmony_ci if (err) { 108062306a36Sopenharmony_ci kfree(dev); 108162306a36Sopenharmony_ci return err; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 108562306a36Sopenharmony_ci if (err) { 108662306a36Sopenharmony_ci kfree(dev); 108762306a36Sopenharmony_ci goto out_budg; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci inode = ubifs_new_inode(c, dir, mode, false); 109362306a36Sopenharmony_ci if (IS_ERR(inode)) { 109462306a36Sopenharmony_ci kfree(dev); 109562306a36Sopenharmony_ci err = PTR_ERR(inode); 109662306a36Sopenharmony_ci goto out_fname; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, rdev); 110062306a36Sopenharmony_ci inode->i_size = ubifs_inode(inode)->ui_size = devlen; 110162306a36Sopenharmony_ci ui = ubifs_inode(inode); 110262306a36Sopenharmony_ci ui->data = dev; 110362306a36Sopenharmony_ci ui->data_len = devlen; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 110662306a36Sopenharmony_ci if (err) 110762306a36Sopenharmony_ci goto out_inode; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 111062306a36Sopenharmony_ci dir->i_size += sz_change; 111162306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 111262306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 111362306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 111462306a36Sopenharmony_ci if (err) 111562306a36Sopenharmony_ci goto out_cancel; 111662306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ubifs_release_budget(c, &req); 111962306a36Sopenharmony_ci insert_inode_hash(inode); 112062306a36Sopenharmony_ci d_instantiate(dentry, inode); 112162306a36Sopenharmony_ci fscrypt_free_filename(&nm); 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ciout_cancel: 112562306a36Sopenharmony_ci dir->i_size -= sz_change; 112662306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 112762306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 112862306a36Sopenharmony_ciout_inode: 112962306a36Sopenharmony_ci make_bad_inode(inode); 113062306a36Sopenharmony_ci iput(inode); 113162306a36Sopenharmony_ciout_fname: 113262306a36Sopenharmony_ci fscrypt_free_filename(&nm); 113362306a36Sopenharmony_ciout_budg: 113462306a36Sopenharmony_ci ubifs_release_budget(c, &req); 113562306a36Sopenharmony_ci return err; 113662306a36Sopenharmony_ci} 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cistatic int ubifs_symlink(struct mnt_idmap *idmap, struct inode *dir, 113962306a36Sopenharmony_ci struct dentry *dentry, const char *symname) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct inode *inode; 114262306a36Sopenharmony_ci struct ubifs_inode *ui; 114362306a36Sopenharmony_ci struct ubifs_inode *dir_ui = ubifs_inode(dir); 114462306a36Sopenharmony_ci struct ubifs_info *c = dir->i_sb->s_fs_info; 114562306a36Sopenharmony_ci int err, sz_change, len = strlen(symname); 114662306a36Sopenharmony_ci struct fscrypt_str disk_link; 114762306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, 114862306a36Sopenharmony_ci .dirtied_ino = 1 }; 114962306a36Sopenharmony_ci struct fscrypt_name nm; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, 115262306a36Sopenharmony_ci symname, dir->i_ino); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA, 115562306a36Sopenharmony_ci &disk_link); 115662306a36Sopenharmony_ci if (err) 115762306a36Sopenharmony_ci return err; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* 116062306a36Sopenharmony_ci * Budget request settings: new inode, new direntry and changing parent 116162306a36Sopenharmony_ci * directory inode. 116262306a36Sopenharmony_ci */ 116362306a36Sopenharmony_ci req.new_ino_d = ALIGN(disk_link.len - 1, 8); 116462306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 116562306a36Sopenharmony_ci if (err) 116662306a36Sopenharmony_ci return err; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci err = ubifs_prepare_create(dir, dentry, &nm); 116962306a36Sopenharmony_ci if (err) 117062306a36Sopenharmony_ci goto out_budg; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci sz_change = CALC_DENT_SIZE(fname_len(&nm)); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO, false); 117562306a36Sopenharmony_ci if (IS_ERR(inode)) { 117662306a36Sopenharmony_ci err = PTR_ERR(inode); 117762306a36Sopenharmony_ci goto out_fname; 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci ui = ubifs_inode(inode); 118162306a36Sopenharmony_ci ui->data = kmalloc(disk_link.len, GFP_NOFS); 118262306a36Sopenharmony_ci if (!ui->data) { 118362306a36Sopenharmony_ci err = -ENOMEM; 118462306a36Sopenharmony_ci goto out_inode; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci if (IS_ENCRYPTED(inode)) { 118862306a36Sopenharmony_ci disk_link.name = ui->data; /* encrypt directly into ui->data */ 118962306a36Sopenharmony_ci err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); 119062306a36Sopenharmony_ci if (err) 119162306a36Sopenharmony_ci goto out_inode; 119262306a36Sopenharmony_ci } else { 119362306a36Sopenharmony_ci memcpy(ui->data, disk_link.name, disk_link.len); 119462306a36Sopenharmony_ci inode->i_link = ui->data; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci /* 119862306a36Sopenharmony_ci * The terminating zero byte is not written to the flash media and it 119962306a36Sopenharmony_ci * is put just to make later in-memory string processing simpler. Thus, 120062306a36Sopenharmony_ci * data length is @disk_link.len - 1, not @disk_link.len. 120162306a36Sopenharmony_ci */ 120262306a36Sopenharmony_ci ui->data_len = disk_link.len - 1; 120362306a36Sopenharmony_ci inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci err = ubifs_init_security(dir, inode, &dentry->d_name); 120662306a36Sopenharmony_ci if (err) 120762306a36Sopenharmony_ci goto out_inode; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci mutex_lock(&dir_ui->ui_mutex); 121062306a36Sopenharmony_ci dir->i_size += sz_change; 121162306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 121262306a36Sopenharmony_ci dir->i_mtime = inode_set_ctime_to_ts(dir, inode_get_ctime(inode)); 121362306a36Sopenharmony_ci err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); 121462306a36Sopenharmony_ci if (err) 121562306a36Sopenharmony_ci goto out_cancel; 121662306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci insert_inode_hash(inode); 121962306a36Sopenharmony_ci d_instantiate(dentry, inode); 122062306a36Sopenharmony_ci err = 0; 122162306a36Sopenharmony_ci goto out_fname; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ciout_cancel: 122462306a36Sopenharmony_ci dir->i_size -= sz_change; 122562306a36Sopenharmony_ci dir_ui->ui_size = dir->i_size; 122662306a36Sopenharmony_ci mutex_unlock(&dir_ui->ui_mutex); 122762306a36Sopenharmony_ciout_inode: 122862306a36Sopenharmony_ci /* Free inode->i_link before inode is marked as bad. */ 122962306a36Sopenharmony_ci fscrypt_free_inode(inode); 123062306a36Sopenharmony_ci make_bad_inode(inode); 123162306a36Sopenharmony_ci iput(inode); 123262306a36Sopenharmony_ciout_fname: 123362306a36Sopenharmony_ci fscrypt_free_filename(&nm); 123462306a36Sopenharmony_ciout_budg: 123562306a36Sopenharmony_ci ubifs_release_budget(c, &req); 123662306a36Sopenharmony_ci return err; 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci/** 124062306a36Sopenharmony_ci * lock_4_inodes - a wrapper for locking three UBIFS inodes. 124162306a36Sopenharmony_ci * @inode1: first inode 124262306a36Sopenharmony_ci * @inode2: second inode 124362306a36Sopenharmony_ci * @inode3: third inode 124462306a36Sopenharmony_ci * @inode4: fourth inode 124562306a36Sopenharmony_ci * 124662306a36Sopenharmony_ci * This function is used for 'ubifs_rename()' and @inode1 may be the same as 124762306a36Sopenharmony_ci * @inode2 whereas @inode3 and @inode4 may be %NULL. 124862306a36Sopenharmony_ci * 124962306a36Sopenharmony_ci * We do not implement any tricks to guarantee strict lock ordering, because 125062306a36Sopenharmony_ci * VFS has already done it for us on the @i_mutex. So this is just a simple 125162306a36Sopenharmony_ci * wrapper function. 125262306a36Sopenharmony_ci */ 125362306a36Sopenharmony_cistatic void lock_4_inodes(struct inode *inode1, struct inode *inode2, 125462306a36Sopenharmony_ci struct inode *inode3, struct inode *inode4) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); 125762306a36Sopenharmony_ci if (inode2 != inode1) 125862306a36Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); 125962306a36Sopenharmony_ci if (inode3) 126062306a36Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3); 126162306a36Sopenharmony_ci if (inode4) 126262306a36Sopenharmony_ci mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4); 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci/** 126662306a36Sopenharmony_ci * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename. 126762306a36Sopenharmony_ci * @inode1: first inode 126862306a36Sopenharmony_ci * @inode2: second inode 126962306a36Sopenharmony_ci * @inode3: third inode 127062306a36Sopenharmony_ci * @inode4: fourth inode 127162306a36Sopenharmony_ci */ 127262306a36Sopenharmony_cistatic void unlock_4_inodes(struct inode *inode1, struct inode *inode2, 127362306a36Sopenharmony_ci struct inode *inode3, struct inode *inode4) 127462306a36Sopenharmony_ci{ 127562306a36Sopenharmony_ci if (inode4) 127662306a36Sopenharmony_ci mutex_unlock(&ubifs_inode(inode4)->ui_mutex); 127762306a36Sopenharmony_ci if (inode3) 127862306a36Sopenharmony_ci mutex_unlock(&ubifs_inode(inode3)->ui_mutex); 127962306a36Sopenharmony_ci if (inode1 != inode2) 128062306a36Sopenharmony_ci mutex_unlock(&ubifs_inode(inode2)->ui_mutex); 128162306a36Sopenharmony_ci mutex_unlock(&ubifs_inode(inode1)->ui_mutex); 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic int do_rename(struct inode *old_dir, struct dentry *old_dentry, 128562306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 128662306a36Sopenharmony_ci unsigned int flags) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci struct ubifs_info *c = old_dir->i_sb->s_fs_info; 128962306a36Sopenharmony_ci struct inode *old_inode = d_inode(old_dentry); 129062306a36Sopenharmony_ci struct inode *new_inode = d_inode(new_dentry); 129162306a36Sopenharmony_ci struct inode *whiteout = NULL; 129262306a36Sopenharmony_ci struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); 129362306a36Sopenharmony_ci struct ubifs_inode *whiteout_ui = NULL; 129462306a36Sopenharmony_ci int err, release, sync = 0, move = (new_dir != old_dir); 129562306a36Sopenharmony_ci int is_dir = S_ISDIR(old_inode->i_mode); 129662306a36Sopenharmony_ci int unlink = !!new_inode, new_sz, old_sz; 129762306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, 129862306a36Sopenharmony_ci .dirtied_ino = 3 }; 129962306a36Sopenharmony_ci struct ubifs_budget_req ino_req = { .dirtied_ino = 1, 130062306a36Sopenharmony_ci .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; 130162306a36Sopenharmony_ci struct ubifs_budget_req wht_req; 130262306a36Sopenharmony_ci unsigned int saved_nlink; 130362306a36Sopenharmony_ci struct fscrypt_name old_nm, new_nm; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci /* 130662306a36Sopenharmony_ci * Budget request settings: 130762306a36Sopenharmony_ci * req: deletion direntry, new direntry, removing the old inode, 130862306a36Sopenharmony_ci * and changing old and new parent directory inodes. 130962306a36Sopenharmony_ci * 131062306a36Sopenharmony_ci * wht_req: new whiteout inode for RENAME_WHITEOUT. 131162306a36Sopenharmony_ci * 131262306a36Sopenharmony_ci * ino_req: marks the target inode as dirty and does not write it. 131362306a36Sopenharmony_ci */ 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x", 131662306a36Sopenharmony_ci old_dentry, old_inode->i_ino, old_dir->i_ino, 131762306a36Sopenharmony_ci new_dentry, new_dir->i_ino, flags); 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (unlink) { 132062306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(new_inode)); 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci /* Budget for old inode's data when its nlink > 1. */ 132362306a36Sopenharmony_ci req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8); 132462306a36Sopenharmony_ci err = ubifs_purge_xattrs(new_inode); 132562306a36Sopenharmony_ci if (err) 132662306a36Sopenharmony_ci return err; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (unlink && is_dir) { 133062306a36Sopenharmony_ci err = ubifs_check_dir_empty(new_inode); 133162306a36Sopenharmony_ci if (err) 133262306a36Sopenharmony_ci return err; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm); 133662306a36Sopenharmony_ci if (err) 133762306a36Sopenharmony_ci return err; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm); 134062306a36Sopenharmony_ci if (err) { 134162306a36Sopenharmony_ci fscrypt_free_filename(&old_nm); 134262306a36Sopenharmony_ci return err; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci new_sz = CALC_DENT_SIZE(fname_len(&new_nm)); 134662306a36Sopenharmony_ci old_sz = CALC_DENT_SIZE(fname_len(&old_nm)); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 134962306a36Sopenharmony_ci if (err) { 135062306a36Sopenharmony_ci fscrypt_free_filename(&old_nm); 135162306a36Sopenharmony_ci fscrypt_free_filename(&new_nm); 135262306a36Sopenharmony_ci return err; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci err = ubifs_budget_space(c, &ino_req); 135562306a36Sopenharmony_ci if (err) { 135662306a36Sopenharmony_ci fscrypt_free_filename(&old_nm); 135762306a36Sopenharmony_ci fscrypt_free_filename(&new_nm); 135862306a36Sopenharmony_ci ubifs_release_budget(c, &req); 135962306a36Sopenharmony_ci return err; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci if (flags & RENAME_WHITEOUT) { 136362306a36Sopenharmony_ci union ubifs_dev_desc *dev = NULL; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); 136662306a36Sopenharmony_ci if (!dev) { 136762306a36Sopenharmony_ci err = -ENOMEM; 136862306a36Sopenharmony_ci goto out_release; 136962306a36Sopenharmony_ci } 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci /* 137262306a36Sopenharmony_ci * The whiteout inode without dentry is pinned in memory, 137362306a36Sopenharmony_ci * umount won't happen during rename process because we 137462306a36Sopenharmony_ci * got parent dentry. 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci whiteout = create_whiteout(old_dir, old_dentry); 137762306a36Sopenharmony_ci if (IS_ERR(whiteout)) { 137862306a36Sopenharmony_ci err = PTR_ERR(whiteout); 137962306a36Sopenharmony_ci kfree(dev); 138062306a36Sopenharmony_ci goto out_release; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci whiteout_ui = ubifs_inode(whiteout); 138462306a36Sopenharmony_ci whiteout_ui->data = dev; 138562306a36Sopenharmony_ci whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); 138662306a36Sopenharmony_ci ubifs_assert(c, !whiteout_ui->dirty); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci memset(&wht_req, 0, sizeof(struct ubifs_budget_req)); 138962306a36Sopenharmony_ci wht_req.new_ino = 1; 139062306a36Sopenharmony_ci wht_req.new_ino_d = ALIGN(whiteout_ui->data_len, 8); 139162306a36Sopenharmony_ci /* 139262306a36Sopenharmony_ci * To avoid deadlock between space budget (holds ui_mutex and 139362306a36Sopenharmony_ci * waits wb work) and writeback work(waits ui_mutex), do space 139462306a36Sopenharmony_ci * budget before ubifs inodes locked. 139562306a36Sopenharmony_ci */ 139662306a36Sopenharmony_ci err = ubifs_budget_space(c, &wht_req); 139762306a36Sopenharmony_ci if (err) { 139862306a36Sopenharmony_ci /* 139962306a36Sopenharmony_ci * Whiteout inode can not be written on flash by 140062306a36Sopenharmony_ci * ubifs_jnl_write_inode(), because it's neither 140162306a36Sopenharmony_ci * dirty nor zero-nlink. 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_ci iput(whiteout); 140462306a36Sopenharmony_ci goto out_release; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* Add the old_dentry size to the old_dir size. */ 140862306a36Sopenharmony_ci old_sz -= CALC_DENT_SIZE(fname_len(&old_nm)); 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci lock_4_inodes(old_dir, new_dir, new_inode, whiteout); 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci /* 141462306a36Sopenharmony_ci * Like most other Unix systems, set the @i_ctime for inodes on a 141562306a36Sopenharmony_ci * rename. 141662306a36Sopenharmony_ci */ 141762306a36Sopenharmony_ci simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* We must adjust parent link count when renaming directories */ 142062306a36Sopenharmony_ci if (is_dir) { 142162306a36Sopenharmony_ci if (move) { 142262306a36Sopenharmony_ci /* 142362306a36Sopenharmony_ci * @old_dir loses a link because we are moving 142462306a36Sopenharmony_ci * @old_inode to a different directory. 142562306a36Sopenharmony_ci */ 142662306a36Sopenharmony_ci drop_nlink(old_dir); 142762306a36Sopenharmony_ci /* 142862306a36Sopenharmony_ci * @new_dir only gains a link if we are not also 142962306a36Sopenharmony_ci * overwriting an existing directory. 143062306a36Sopenharmony_ci */ 143162306a36Sopenharmony_ci if (!unlink) 143262306a36Sopenharmony_ci inc_nlink(new_dir); 143362306a36Sopenharmony_ci } else { 143462306a36Sopenharmony_ci /* 143562306a36Sopenharmony_ci * @old_inode is not moving to a different directory, 143662306a36Sopenharmony_ci * but @old_dir still loses a link if we are 143762306a36Sopenharmony_ci * overwriting an existing directory. 143862306a36Sopenharmony_ci */ 143962306a36Sopenharmony_ci if (unlink) 144062306a36Sopenharmony_ci drop_nlink(old_dir); 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci old_dir->i_size -= old_sz; 144562306a36Sopenharmony_ci ubifs_inode(old_dir)->ui_size = old_dir->i_size; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* 144862306a36Sopenharmony_ci * And finally, if we unlinked a direntry which happened to have the 144962306a36Sopenharmony_ci * same name as the moved direntry, we have to decrement @i_nlink of 145062306a36Sopenharmony_ci * the unlinked inode. 145162306a36Sopenharmony_ci */ 145262306a36Sopenharmony_ci if (unlink) { 145362306a36Sopenharmony_ci /* 145462306a36Sopenharmony_ci * Directories cannot have hard-links, so if this is a 145562306a36Sopenharmony_ci * directory, just clear @i_nlink. 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_ci saved_nlink = new_inode->i_nlink; 145862306a36Sopenharmony_ci if (is_dir) 145962306a36Sopenharmony_ci clear_nlink(new_inode); 146062306a36Sopenharmony_ci else 146162306a36Sopenharmony_ci drop_nlink(new_inode); 146262306a36Sopenharmony_ci } else { 146362306a36Sopenharmony_ci new_dir->i_size += new_sz; 146462306a36Sopenharmony_ci ubifs_inode(new_dir)->ui_size = new_dir->i_size; 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci /* 146862306a36Sopenharmony_ci * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode 146962306a36Sopenharmony_ci * is dirty, because this will be done later on at the end of 147062306a36Sopenharmony_ci * 'ubifs_rename()'. 147162306a36Sopenharmony_ci */ 147262306a36Sopenharmony_ci if (IS_SYNC(old_inode)) { 147362306a36Sopenharmony_ci sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); 147462306a36Sopenharmony_ci if (unlink && IS_SYNC(new_inode)) 147562306a36Sopenharmony_ci sync = 1; 147662306a36Sopenharmony_ci /* 147762306a36Sopenharmony_ci * S_SYNC flag of whiteout inherits from the old_dir, and we 147862306a36Sopenharmony_ci * have already checked the old dir inode. So there is no need 147962306a36Sopenharmony_ci * to check whiteout. 148062306a36Sopenharmony_ci */ 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir, 148462306a36Sopenharmony_ci new_inode, &new_nm, whiteout, sync); 148562306a36Sopenharmony_ci if (err) 148662306a36Sopenharmony_ci goto out_cancel; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); 148962306a36Sopenharmony_ci ubifs_release_budget(c, &req); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (whiteout) { 149262306a36Sopenharmony_ci ubifs_release_budget(c, &wht_req); 149362306a36Sopenharmony_ci iput(whiteout); 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci mutex_lock(&old_inode_ui->ui_mutex); 149762306a36Sopenharmony_ci release = old_inode_ui->dirty; 149862306a36Sopenharmony_ci mark_inode_dirty_sync(old_inode); 149962306a36Sopenharmony_ci mutex_unlock(&old_inode_ui->ui_mutex); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (release) 150262306a36Sopenharmony_ci ubifs_release_budget(c, &ino_req); 150362306a36Sopenharmony_ci if (IS_SYNC(old_inode)) 150462306a36Sopenharmony_ci /* 150562306a36Sopenharmony_ci * Rename finished here. Although old inode cannot be updated 150662306a36Sopenharmony_ci * on flash, old ctime is not a big problem, don't return err 150762306a36Sopenharmony_ci * code to userspace. 150862306a36Sopenharmony_ci */ 150962306a36Sopenharmony_ci old_inode->i_sb->s_op->write_inode(old_inode, NULL); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci fscrypt_free_filename(&old_nm); 151262306a36Sopenharmony_ci fscrypt_free_filename(&new_nm); 151362306a36Sopenharmony_ci return 0; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ciout_cancel: 151662306a36Sopenharmony_ci if (unlink) { 151762306a36Sopenharmony_ci set_nlink(new_inode, saved_nlink); 151862306a36Sopenharmony_ci } else { 151962306a36Sopenharmony_ci new_dir->i_size -= new_sz; 152062306a36Sopenharmony_ci ubifs_inode(new_dir)->ui_size = new_dir->i_size; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci old_dir->i_size += old_sz; 152362306a36Sopenharmony_ci ubifs_inode(old_dir)->ui_size = old_dir->i_size; 152462306a36Sopenharmony_ci if (is_dir) { 152562306a36Sopenharmony_ci if (move) { 152662306a36Sopenharmony_ci inc_nlink(old_dir); 152762306a36Sopenharmony_ci if (!unlink) 152862306a36Sopenharmony_ci drop_nlink(new_dir); 152962306a36Sopenharmony_ci } else { 153062306a36Sopenharmony_ci if (unlink) 153162306a36Sopenharmony_ci inc_nlink(old_dir); 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); 153562306a36Sopenharmony_ci if (whiteout) { 153662306a36Sopenharmony_ci ubifs_release_budget(c, &wht_req); 153762306a36Sopenharmony_ci iput(whiteout); 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ciout_release: 154062306a36Sopenharmony_ci ubifs_release_budget(c, &ino_req); 154162306a36Sopenharmony_ci ubifs_release_budget(c, &req); 154262306a36Sopenharmony_ci fscrypt_free_filename(&old_nm); 154362306a36Sopenharmony_ci fscrypt_free_filename(&new_nm); 154462306a36Sopenharmony_ci return err; 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_cistatic int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, 154862306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct ubifs_info *c = old_dir->i_sb->s_fs_info; 155162306a36Sopenharmony_ci struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, 155262306a36Sopenharmony_ci .dirtied_ino = 2 }; 155362306a36Sopenharmony_ci int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); 155462306a36Sopenharmony_ci struct inode *fst_inode = d_inode(old_dentry); 155562306a36Sopenharmony_ci struct inode *snd_inode = d_inode(new_dentry); 155662306a36Sopenharmony_ci int err; 155762306a36Sopenharmony_ci struct fscrypt_name fst_nm, snd_nm; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci ubifs_assert(c, fst_inode && snd_inode); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci /* 156262306a36Sopenharmony_ci * Budget request settings: changing two direntries, changing the two 156362306a36Sopenharmony_ci * parent directory inodes. 156462306a36Sopenharmony_ci */ 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci dbg_gen("dent '%pd' ino %lu in dir ino %lu exchange dent '%pd' ino %lu in dir ino %lu", 156762306a36Sopenharmony_ci old_dentry, fst_inode->i_ino, old_dir->i_ino, 156862306a36Sopenharmony_ci new_dentry, snd_inode->i_ino, new_dir->i_ino); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm); 157162306a36Sopenharmony_ci if (err) 157262306a36Sopenharmony_ci return err; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &snd_nm); 157562306a36Sopenharmony_ci if (err) { 157662306a36Sopenharmony_ci fscrypt_free_filename(&fst_nm); 157762306a36Sopenharmony_ci return err; 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci err = ubifs_budget_space(c, &req); 158162306a36Sopenharmony_ci if (err) 158262306a36Sopenharmony_ci goto out; 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci lock_4_inodes(old_dir, new_dir, NULL, NULL); 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (old_dir != new_dir) { 158962306a36Sopenharmony_ci if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { 159062306a36Sopenharmony_ci inc_nlink(new_dir); 159162306a36Sopenharmony_ci drop_nlink(old_dir); 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { 159462306a36Sopenharmony_ci drop_nlink(new_dir); 159562306a36Sopenharmony_ci inc_nlink(old_dir); 159662306a36Sopenharmony_ci } 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir, 160062306a36Sopenharmony_ci snd_inode, &snd_nm, sync); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci unlock_4_inodes(old_dir, new_dir, NULL, NULL); 160362306a36Sopenharmony_ci ubifs_release_budget(c, &req); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ciout: 160662306a36Sopenharmony_ci fscrypt_free_filename(&fst_nm); 160762306a36Sopenharmony_ci fscrypt_free_filename(&snd_nm); 160862306a36Sopenharmony_ci return err; 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic int ubifs_rename(struct mnt_idmap *idmap, 161262306a36Sopenharmony_ci struct inode *old_dir, struct dentry *old_dentry, 161362306a36Sopenharmony_ci struct inode *new_dir, struct dentry *new_dentry, 161462306a36Sopenharmony_ci unsigned int flags) 161562306a36Sopenharmony_ci{ 161662306a36Sopenharmony_ci int err; 161762306a36Sopenharmony_ci struct ubifs_info *c = old_dir->i_sb->s_fs_info; 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE)) 162062306a36Sopenharmony_ci return -EINVAL; 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(old_dir)); 162362306a36Sopenharmony_ci ubifs_assert(c, inode_is_locked(new_dir)); 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci err = fscrypt_prepare_rename(old_dir, old_dentry, new_dir, new_dentry, 162662306a36Sopenharmony_ci flags); 162762306a36Sopenharmony_ci if (err) 162862306a36Sopenharmony_ci return err; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) 163162306a36Sopenharmony_ci return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags); 163462306a36Sopenharmony_ci} 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ciint ubifs_getattr(struct mnt_idmap *idmap, const struct path *path, 163762306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, unsigned int flags) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci loff_t size; 164062306a36Sopenharmony_ci struct inode *inode = d_inode(path->dentry); 164162306a36Sopenharmony_ci struct ubifs_inode *ui = ubifs_inode(inode); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci mutex_lock(&ui->ui_mutex); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci if (ui->flags & UBIFS_APPEND_FL) 164662306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_APPEND; 164762306a36Sopenharmony_ci if (ui->flags & UBIFS_COMPR_FL) 164862306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_COMPRESSED; 164962306a36Sopenharmony_ci if (ui->flags & UBIFS_CRYPT_FL) 165062306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_ENCRYPTED; 165162306a36Sopenharmony_ci if (ui->flags & UBIFS_IMMUTABLE_FL) 165262306a36Sopenharmony_ci stat->attributes |= STATX_ATTR_IMMUTABLE; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci stat->attributes_mask |= (STATX_ATTR_APPEND | 165562306a36Sopenharmony_ci STATX_ATTR_COMPRESSED | 165662306a36Sopenharmony_ci STATX_ATTR_ENCRYPTED | 165762306a36Sopenharmony_ci STATX_ATTR_IMMUTABLE); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 166062306a36Sopenharmony_ci stat->blksize = UBIFS_BLOCK_SIZE; 166162306a36Sopenharmony_ci stat->size = ui->ui_size; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci /* 166462306a36Sopenharmony_ci * Unfortunately, the 'stat()' system call was designed for block 166562306a36Sopenharmony_ci * device based file systems, and it is not appropriate for UBIFS, 166662306a36Sopenharmony_ci * because UBIFS does not have notion of "block". For example, it is 166762306a36Sopenharmony_ci * difficult to tell how many block a directory takes - it actually 166862306a36Sopenharmony_ci * takes less than 300 bytes, but we have to round it to block size, 166962306a36Sopenharmony_ci * which introduces large mistake. This makes utilities like 'du' to 167062306a36Sopenharmony_ci * report completely senseless numbers. This is the reason why UBIFS 167162306a36Sopenharmony_ci * goes the same way as JFFS2 - it reports zero blocks for everything 167262306a36Sopenharmony_ci * but regular files, which makes more sense than reporting completely 167362306a36Sopenharmony_ci * wrong sizes. 167462306a36Sopenharmony_ci */ 167562306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 167662306a36Sopenharmony_ci size = ui->xattr_size; 167762306a36Sopenharmony_ci size += stat->size; 167862306a36Sopenharmony_ci size = ALIGN(size, UBIFS_BLOCK_SIZE); 167962306a36Sopenharmony_ci /* 168062306a36Sopenharmony_ci * Note, user-space expects 512-byte blocks count irrespectively 168162306a36Sopenharmony_ci * of what was reported in @stat->size. 168262306a36Sopenharmony_ci */ 168362306a36Sopenharmony_ci stat->blocks = size >> 9; 168462306a36Sopenharmony_ci } else 168562306a36Sopenharmony_ci stat->blocks = 0; 168662306a36Sopenharmony_ci mutex_unlock(&ui->ui_mutex); 168762306a36Sopenharmony_ci return 0; 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ciconst struct inode_operations ubifs_dir_inode_operations = { 169162306a36Sopenharmony_ci .lookup = ubifs_lookup, 169262306a36Sopenharmony_ci .create = ubifs_create, 169362306a36Sopenharmony_ci .link = ubifs_link, 169462306a36Sopenharmony_ci .symlink = ubifs_symlink, 169562306a36Sopenharmony_ci .unlink = ubifs_unlink, 169662306a36Sopenharmony_ci .mkdir = ubifs_mkdir, 169762306a36Sopenharmony_ci .rmdir = ubifs_rmdir, 169862306a36Sopenharmony_ci .mknod = ubifs_mknod, 169962306a36Sopenharmony_ci .rename = ubifs_rename, 170062306a36Sopenharmony_ci .setattr = ubifs_setattr, 170162306a36Sopenharmony_ci .getattr = ubifs_getattr, 170262306a36Sopenharmony_ci .listxattr = ubifs_listxattr, 170362306a36Sopenharmony_ci .update_time = ubifs_update_time, 170462306a36Sopenharmony_ci .tmpfile = ubifs_tmpfile, 170562306a36Sopenharmony_ci .fileattr_get = ubifs_fileattr_get, 170662306a36Sopenharmony_ci .fileattr_set = ubifs_fileattr_set, 170762306a36Sopenharmony_ci}; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ciconst struct file_operations ubifs_dir_operations = { 171062306a36Sopenharmony_ci .llseek = generic_file_llseek, 171162306a36Sopenharmony_ci .release = ubifs_dir_release, 171262306a36Sopenharmony_ci .read = generic_read_dir, 171362306a36Sopenharmony_ci .iterate_shared = ubifs_readdir, 171462306a36Sopenharmony_ci .fsync = ubifs_fsync, 171562306a36Sopenharmony_ci .unlocked_ioctl = ubifs_ioctl, 171662306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 171762306a36Sopenharmony_ci .compat_ioctl = ubifs_compat_ioctl, 171862306a36Sopenharmony_ci#endif 171962306a36Sopenharmony_ci}; 1720