// SPDX-License-Identifier: GPL-2.0-only /* * This file is part of UBIFS. * * Copyright (C) 2006-2008 Nokia Corporation. * Copyright (C) 2006, 2007 University of Szeged, Hungary * * Authors: Artem Bityutskiy (Битюцкий Артём) * Adrian Hunter * Zoltan Sogor
*/
/* * This file implements directory operations. * * All FS operations in this file allocate budget before writing anything to the * media. If they fail to allocate it, the error is returned. The only * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even * if they unable to allocate the budget, because deletion %-ENOSPC failure is * not what users are usually ready to get. UBIFS budgeting subsystem has some * space reserved for these purposes. * * All operations in this file write all inodes which they change straight * away, instead of marking them dirty. For example, 'ubifs_link()' changes * @i_size of the parent inode and writes the parent inode together with the * target inode. This was done to simplify file-system recovery which would * otherwise be very difficult to do. The only exception is rename which marks * the re-named inode dirty (because its @i_ctime is updated) but does not * write it, but just marks it as dirty.
*/
#include"ubifs.h"
/** * inherit_flags - inherit flags of the parent inode. * @dir: parent inode * @mode: new inode mode flags * * This is a helper function for 'ubifs_new_inode()' which inherits flag of the * parent directory inode @dir. UBIFS inodes inherit the following flags: * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on * sub-directory basis; * o %UBIFS_SYNC_FL - useful for the same reasons; * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories. * * This function returns the inherited flags.
*/ staticint inherit_flags(conststruct inode *dir, umode_t mode)
{ int flags; conststruct ubifs_inode *ui = ubifs_inode(dir);
if (!S_ISDIR(dir->i_mode)) /* * The parent is not a directory, which means that an extended * attribute inode is being created. No flags.
*/ return 0;
flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); if (!S_ISDIR(mode)) /* The "DIRSYNC" flag only applies to directories */
flags &= ~UBIFS_DIRSYNC_FL; return flags;
}
/** * ubifs_new_inode - allocate new UBIFS inode object. * @c: UBIFS file-system description object * @dir: parent directory inode * @mode: inode mode flags * @is_xattr: whether the inode is xattr inode * * This function finds an unused inode number, allocates new inode and * initializes it. Non-xattr new inode may be written with xattrs(selinux/ * encryption) before writing dentry, which could cause inconsistent problem * when powercut happens between two operations. To deal with it, non-xattr * new inode is initialized with zero-nlink and added into orphan list, caller * should make sure that inode is relinked later, and make sure that orphan * removing and journal writing into an committing atomic operation. Returns * new inode in case of success and an error code in case of failure.
*/ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
umode_t mode, bool is_xattr)
{ int err; struct inode *inode; struct ubifs_inode *ui; bool encrypted = false;
inode = new_inode(c->vfs_sb);
ui = ubifs_inode(inode); if (!inode) return ERR_PTR(-ENOMEM);
/* * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and * marking them dirty in file write path (see 'file_update_time()'). * UBIFS has to fully control "clean <-> dirty" transitions of inodes * to make budgeting work.
*/
inode->i_flags |= S_NOCMTIME;
spin_lock(&c->cnt_lock); /* Inode number overflow is currently not supported */ if (c->highest_inum >= INUM_WARN_WATERMARK) { if (c->highest_inum >= INUM_WATERMARK) {
spin_unlock(&c->cnt_lock);
ubifs_err(c, "out of inode numbers");
err = -EINVAL; goto out_iput;
}
ubifs_warn(c, "running out of inode numbers (current %lu, max %u)",
(unsignedlong)c->highest_inum, INUM_WATERMARK);
}
inode->i_ino = ++c->highest_inum; /* * The creation sequence number remains with this inode for its * lifetime. All nodes for this inode have a greater sequence number, * and so it is possible to distinguish obsolete nodes belonging to a * previous incarnation of the same inode number - for example, for the * purpose of rebuilding the index.
*/
ui->creat_sqnum = ++c->max_sqnum;
spin_unlock(&c->cnt_lock);
/* * Create an inode('nlink = 1') for whiteout without updating journal, * let ubifs_jnl_rename() store it on flash to complete rename whiteout * atomically.
*/
dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
dentry, mode, dir->i_ino);
/** * lock_2_inodes - a wrapper for locking two UBIFS inodes. * @inode1: first inode * @inode2: second inode * * We do not implement any tricks to guarantee strict lock ordering, because * VFS has already done it for us on the @i_mutex. So this is just a simple * wrapper function.
*/ staticvoid lock_2_inodes(struct inode *inode1, struct inode *inode2)
{
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1);
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2);
}
/** * unlock_2_inodes - a wrapper for unlocking two UBIFS inodes. * @inode1: first inode * @inode2: second inode
*/ staticvoid unlock_2_inodes(struct inode *inode1, struct inode *inode2)
{
mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
}
/* * Budget request settings: new inode, new direntry, changing the * parent directory inode. * Allocate budget separately for new dirtied inode, the budget will * be released via writeback.
*/
dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
dentry, mode, dir->i_ino);
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) return err;
/* * The classical Unix view for directory is that it is a linear array of * (name, inode number) entries. Linux/VFS assumes this model as well. * Particularly, 'readdir()' call wants us to return a directory entry offset * which later may be used to continue 'readdir()'ing the directory or to * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this * model because directory entries are identified by keys, which may collide. * * UBIFS uses directory entry hash value for directory offsets, so * 'seekdir()'/'telldir()' may not always work because of possible key * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work * properly by means of saving full directory entry name in the private field * of the file description object. * * This means that UBIFS cannot support NFS which requires full * 'seekdir()'/'telldir()' support.
*/ staticint ubifs_readdir(struct file *file, struct dir_context *ctx)
{ int fstr_real_len = 0, err = 0; struct fscrypt_name nm; struct fscrypt_str fstr = {0}; union ubifs_key key; struct ubifs_dent_node *dent; struct inode *dir = file_inode(file); struct ubifs_info *c = dir->i_sb->s_fs_info; bool encrypted = IS_ENCRYPTED(dir); struct ubifs_dir_data *data = file->private_data;
if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2) /* * The directory was seek'ed to a senseless position or there * are no more entries.
*/ return 0;
if (encrypted) {
err = fscrypt_prepare_readdir(dir); if (err) return err;
err = fscrypt_fname_alloc_buffer(UBIFS_MAX_NLEN, &fstr); if (err) return err;
fstr_real_len = fstr.len;
}
if (data->cookie == 0) { /* * The file was seek'ed, which means that @data->dent * is now invalid. This may also be just the first * 'ubifs_readdir()' invocation, in which case * @data->dent is NULL, and the below code is * basically a no-op.
*/
kfree(data->dent);
data->dent = NULL;
}
/* * 'ubifs_dir_llseek()' sets @data->cookie to zero, and we use this * for detecting whether the file was seek'ed.
*/
data->cookie = 1;
/* File positions 0 and 1 correspond to "." and ".." */ if (ctx->pos < 2) {
ubifs_assert(c, !data->dent); if (!dir_emit_dots(file, ctx)) { if (encrypted)
fscrypt_fname_free_buffer(&fstr); return 0;
}
/* Find the first entry in TNC and save it */
lowest_dent_key(c, &key, dir->i_ino);
fname_len(&nm) = 0;
dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) {
err = PTR_ERR(dent); goto out;
}
dent = data->dent; if (!dent) { /* * The directory was seek'ed to and is now readdir'ed. * Find the entry corresponding to @ctx->pos or the closest one.
*/
dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
fname_len(&nm) = 0;
dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) {
err = PTR_ERR(dent); goto out;
}
ctx->pos = key_hash_flash(c, &dent->key);
data->dent = dent;
}
while (1) {
dbg_gen("ino %llu, new f_pos %#x",
(unsignedlonglong)le64_to_cpu(dent->inum),
key_hash_flash(c, &dent->key));
ubifs_assert(c, le64_to_cpu(dent->ch.sqnum) >
ubifs_inode(dir)->creat_sqnum);
if (err != -ENOENT)
ubifs_err(c, "cannot find next direntry, error %d", err); else /* * -ENOENT is a non-fatal error in this context, the TNC uses * it to indicate that the cursor moved past the current directory * and readdir() has to stop.
*/
err = 0;
/* 2 is a special value indicating that there are no more direntries */
ctx->pos = 2; return err;
}
/* Free saved readdir() state when the directory is closed */ staticint ubifs_dir_release(struct inode *dir, struct file *file)
{ struct ubifs_dir_data *data = file->private_data;
/* * Budget request settings: deletion direntry, deletion inode (+1 for * @dirtied_ino), changing the parent directory inode. If budgeting * fails, go ahead anyway because we have extra space reserved for * deletions.
*/
dbg_gen("dent '%pd' from ino %lu (nlink %d) in dir ino %lu",
dentry, inode->i_ino,
inode->i_nlink, dir->i_ino);
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); if (err) return err;
err = ubifs_purge_xattrs(inode); if (err) return err;
/** * ubifs_check_dir_empty - check if a directory is empty or not. * @dir: VFS inode object of the directory to check * * This function checks if directory @dir is empty. Returns zero if the * directory is empty, %-ENOTEMPTY if it is not, and other negative error codes * in case of errors.
*/ int ubifs_check_dir_empty(struct inode *dir)
{ struct ubifs_info *c = dir->i_sb->s_fs_info; struct fscrypt_name nm = { 0 }; struct ubifs_dent_node *dent; union ubifs_key key; int err;
/* * Budget request settings: deletion direntry, deletion inode and * changing the parent inode. If budgeting fails, go ahead anyway * because we have extra space reserved for deletions.
*/
dbg_gen("directory '%pd', ino %lu in dir ino %lu", dentry,
inode->i_ino, dir->i_ino);
ubifs_assert(c, inode_is_locked(dir));
ubifs_assert(c, inode_is_locked(inode));
err = ubifs_check_dir_empty(d_inode(dentry)); if (err) return err;
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); if (err) return err;
err = ubifs_purge_xattrs(inode); if (err) return err;
sz_change = CALC_DENT_SIZE(fname_len(&nm));
err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) goto out_fname;
budgeted = 0;
}
/* * The terminating zero byte is not written to the flash media and it * is put just to make later in-memory string processing simpler. Thus, * data length is @disk_link.len - 1, not @disk_link.len.
*/
ui->data_len = disk_link.len - 1;
inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1;
set_nlink(inode, 1);
/** * lock_4_inodes - a wrapper for locking three UBIFS inodes. * @inode1: first inode * @inode2: second inode * @inode3: third inode * @inode4: fourth inode * * This function is used for 'ubifs_rename()' and @inode1 may be the same as * @inode2 whereas @inode3 and @inode4 may be %NULL. * * We do not implement any tricks to guarantee strict lock ordering, because * VFS has already done it for us on the @i_mutex. So this is just a simple * wrapper function.
*/ staticvoid lock_4_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3, struct inode *inode4)
{
mutex_lock_nested(&ubifs_inode(inode1)->ui_mutex, WB_MUTEX_1); if (inode2 != inode1)
mutex_lock_nested(&ubifs_inode(inode2)->ui_mutex, WB_MUTEX_2); if (inode3)
mutex_lock_nested(&ubifs_inode(inode3)->ui_mutex, WB_MUTEX_3); if (inode4)
mutex_lock_nested(&ubifs_inode(inode4)->ui_mutex, WB_MUTEX_4);
}
/** * unlock_4_inodes - a wrapper for unlocking three UBIFS inodes for rename. * @inode1: first inode * @inode2: second inode * @inode3: third inode * @inode4: fourth inode
*/ staticvoid unlock_4_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3, struct inode *inode4)
{ if (inode4)
mutex_unlock(&ubifs_inode(inode4)->ui_mutex); if (inode3)
mutex_unlock(&ubifs_inode(inode3)->ui_mutex); if (inode1 != inode2)
mutex_unlock(&ubifs_inode(inode2)->ui_mutex);
mutex_unlock(&ubifs_inode(inode1)->ui_mutex);
}
/* * Budget request settings: * req: deletion direntry, new direntry, removing the old inode, * and changing old and new parent directory inodes. * * wht_req: new whiteout inode for RENAME_WHITEOUT. * * ino_req: marks the target inode as dirty and does not write it.
*/
dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu flags 0x%x",
old_dentry, old_inode->i_ino, old_dir->i_ino,
new_dentry, new_dir->i_ino, flags);
if (unlink) {
ubifs_assert(c, inode_is_locked(new_inode));
/* Budget for old inode's data when its nlink > 1. */
req.dirtied_ino_d = ALIGN(ubifs_inode(new_inode)->data_len, 8);
err = ubifs_purge_xattrs(new_inode); if (err) return err;
}
if (unlink && is_dir) {
err = ubifs_check_dir_empty(new_inode); if (err) return err;
}
err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &old_nm); if (err) return err;
if (flags & RENAME_WHITEOUT) { union ubifs_dev_desc *dev = NULL;
dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) {
err = -ENOMEM; goto out_release;
}
/* * The whiteout inode without dentry is pinned in memory, * umount won't happen during rename process because we * got parent dentry.
*/
whiteout = create_whiteout(old_dir, old_dentry); if (IS_ERR(whiteout)) {
err = PTR_ERR(whiteout);
kfree(dev); goto out_release;
}
/* * Like most other Unix systems, set the @i_ctime for inodes on a * rename.
*/
simple_rename_timestamp(old_dir, old_dentry, new_dir, new_dentry);
/* We must adjust parent link count when renaming directories */ if (is_dir) { if (move) { /* * @old_dir loses a link because we are moving * @old_inode to a different directory.
*/
drop_nlink(old_dir); /* * @new_dir only gains a link if we are not also * overwriting an existing directory.
*/ if (!unlink)
inc_nlink(new_dir);
} else { /* * @old_inode is not moving to a different directory, * but @old_dir still loses a link if we are * overwriting an existing directory.
*/ if (unlink)
drop_nlink(old_dir);
}
}
/* * And finally, if we unlinked a direntry which happened to have the * same name as the moved direntry, we have to decrement @i_nlink of * the unlinked inode.
*/ if (unlink) { /* * Directories cannot have hard-links, so if this is a * directory, just clear @i_nlink.
*/
saved_nlink = new_inode->i_nlink; if (is_dir)
clear_nlink(new_inode); else
drop_nlink(new_inode);
} else {
new_dir->i_size += new_sz;
ubifs_inode(new_dir)->ui_size = new_dir->i_size;
}
/* * Do not ask 'ubifs_jnl_rename()' to flush write-buffer if @old_inode * is dirty, because this will be done later on at the end of * 'ubifs_rename()'.
*/ if (IS_SYNC(old_inode)) {
sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); if (unlink && IS_SYNC(new_inode))
sync = 1; /* * S_SYNC flag of whiteout inherits from the old_dir, and we * have already checked the old dir inode. So there is no need * to check whiteout.
*/
}
if (release)
ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) /* * Rename finished here. Although old inode cannot be updated * on flash, old ctime is not a big problem, don't return err * code to userspace.
*/
old_inode->i_sb->s_op->write_inode(old_inode, NULL);
/* * Unfortunately, the 'stat()' system call was designed for block * device based file systems, and it is not appropriate for UBIFS, * because UBIFS does not have notion of "block". For example, it is * difficult to tell how many block a directory takes - it actually * takes less than 300 bytes, but we have to round it to block size, * which introduces large mistake. This makes utilities like 'du' to * report completely senseless numbers. This is the reason why UBIFS * goes the same way as JFFS2 - it reports zero blocks for everything * but regular files, which makes more sense than reporting completely * wrong sizes.
*/ if (S_ISREG(inode->i_mode)) {
size = ui->xattr_size;
size += stat->size;
size = ALIGN(size, UBIFS_BLOCK_SIZE); /* * Note, user-space expects 512-byte blocks count irrespectively * of what was reported in @stat->size.
*/
stat->blocks = size >> 9;
} else
stat->blocks = 0;
mutex_unlock(&ui->ui_mutex); return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.