static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(old_dentry); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, .dirtied_ino_d = ALIGN(ui->data_len, 8) }; /* * Budget request settings: new direntry, changing the target inode, * changing the parent inode. */ dbg_gen("dent '%pd' to ino %lu (nlink %d) in dir ino %lu", dentry, inode->i_ino, inode->i_nlink, dir->i_ino); ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); err = dbg_check_synced_i_size(c, inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) return err; lock_2_inodes(dir, inode); inc_nlink(inode); ihold(inode); inode->i_ctime = ubifs_current_time(inode); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(inode); unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); iput(inode); return err; } static int ubifs_unlink(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(dentry); struct ubifs_inode *dir_ui = ubifs_inode(dir); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; unsigned int saved_nlink = inode->i_nlink; /* * 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); ubifs_assert(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); err = dbg_check_synced_i_size(c, inode); if (err) return err; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) return err; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = ubifs_current_time(dir); drop_nlink(inode); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; set_nlink(inode, saved_nlink); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); return err; } /** * check_dir_empty - check if a directory is empty or not. * @c: UBIFS file-system description object * @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 of errors. */ static int check_dir_empty(struct ubifs_info *c, struct inode *dir) { struct qstr nm = { .name = NULL }; struct ubifs_dent_node *dent; union ubifs_key key; int err; lowest_dent_key(c, &key, dir->i_ino); dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); if (err == -ENOENT) err = 0; } else { kfree(dent); err = -ENOTEMPTY; } return err; } static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(dentry); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, budgeted = 1; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; /* * 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(mutex_is_locked(&dir->i_mutex)); ubifs_assert(mutex_is_locked(&inode->i_mutex)); err = check_dir_empty(c, d_inode(dentry)); if (err) return err; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) return err; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = ubifs_current_time(dir); clear_nlink(inode); drop_nlink(dir); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; inc_nlink(dir); set_nlink(inode, 2); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); return err; } static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dentry, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); insert_inode_hash(inode); inc_nlink(inode); inc_nlink(dir); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) { ubifs_err(c, "cannot create directory, error %d", err); goto out_cancel; } mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(dir); mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; union ubifs_dev_desc *dev = NULL; int sz_change = CALC_DENT_SIZE(dentry->d_name.len); int err, devlen = 0; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(devlen, 8), .dirtied_ino = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino); if (!new_valid_dev(rdev)) return -EINVAL; if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) return -ENOMEM; devlen = ubifs_encode_dev(dev, rdev); } err = ubifs_budget_space(c, &req); if (err) { kfree(dev); return err; } inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { kfree(dev); err = PTR_ERR(inode); goto out_budg; } init_special_inode(inode, inode->i_mode, rdev); inode->i_size = ubifs_inode(inode)->ui_size = devlen; ui = ubifs_inode(inode); ui->data = dev; ui->data_len = devlen; err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, len = strlen(symname); int sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, symname, dir->i_ino); if (len > UBIFS_MAX_INO_DATA) return -ENAMETOOLONG; err = ubifs_budget_space(c, &req); if (err) return err; inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; } ui = ubifs_inode(inode); ui->data = kmalloc(len + 1, GFP_NOFS); if (!ui->data) { err = -ENOMEM; goto out_inode; } memcpy(ui->data, symname, len); ((char *)ui->data)[len] = '\0'; inode->i_link = ui->data; /* * 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 @len, not @len + %1. */ ui->data_len = len; inode->i_size = ubifs_inode(inode)->ui_size = len; err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_budg: ubifs_release_budget(c, &req); return err; } /** * lock_3_inodes - a wrapper for locking three UBIFS inodes. * @inode1: first inode * @inode2: second inode * @inode3: third inode * * This function is used for 'ubifs_rename()' and @inode1 may be the same as * @inode2 whereas @inode3 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. */ static void lock_3_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3) { 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); } /** * unlock_3_inodes - a wrapper for unlocking three UBIFS inodes for rename. * @inode1: first inode * @inode2: second inode * @inode3: third inode */ static void unlock_3_inodes(struct inode *inode1, struct inode *inode2, struct inode *inode3) { 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); } static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct inode *old_inode = d_inode(old_dentry); struct inode *new_inode = d_inode(new_dentry); struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); int err, release, sync = 0, move = (new_dir != old_dir); int is_dir = S_ISDIR(old_inode->i_mode); int unlink = !!new_inode; int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len); int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 3 }; struct ubifs_budget_req ino_req = { .dirtied_ino = 1, .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; struct timespec time; unsigned int uninitialized_var(saved_nlink); /* * Budget request settings: deletion direntry, new direntry, removing * the old inode, and changing old and new parent directory inodes. * * However, this operation also marks the target inode as dirty and * does not write it, so we allocate budget for the target inode * separately. */ dbg_gen("dent '%pd' ino %lu in dir ino %lu to dent '%pd' in dir ino %lu", old_dentry, old_inode->i_ino, old_dir->i_ino, new_dentry, new_dir->i_ino); ubifs_assert(mutex_is_locked(&old_dir->i_mutex)); ubifs_assert(mutex_is_locked(&new_dir->i_mutex)); if (unlink) ubifs_assert(mutex_is_locked(&new_inode->i_mutex)); if (unlink && is_dir) { err = check_dir_empty(c, new_inode); if (err) return err; } err = ubifs_budget_space(c, &req); if (err) return err; err = ubifs_budget_space(c, &ino_req); if (err) { ubifs_release_budget(c, &req); return err; } lock_3_inodes(old_dir, new_dir, new_inode); /* * Like most other Unix systems, set the @i_ctime for inodes on a * rename. */ time = ubifs_current_time(old_dir); old_inode->i_ctime = time; /* 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); } } old_dir->i_size -= old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; /* * 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 and change its ctime. */ 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); new_inode->i_ctime = time; } 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; } err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, sync); if (err) goto out_cancel; unlock_3_inodes(old_dir, new_dir, new_inode); ubifs_release_budget(c, &req); mutex_lock(&old_inode_ui->ui_mutex); release = old_inode_ui->dirty; mark_inode_dirty_sync(old_inode); mutex_unlock(&old_inode_ui->ui_mutex); if (release) ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) err = old_inode->i_sb->s_op->write_inode(old_inode, NULL); return err; out_cancel: if (unlink) { set_nlink(new_inode, saved_nlink); } else { new_dir->i_size -= new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } old_dir->i_size += old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; if (is_dir) { if (move) { inc_nlink(old_dir); if (!unlink) drop_nlink(new_dir); } else { if (unlink) inc_nlink(old_dir); } } unlock_3_inodes(old_dir, new_dir, new_inode); ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &req); return err; } int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { loff_t size; struct inode *inode = d_inode(dentry); struct ubifs_inode *ui = ubifs_inode(inode); mutex_lock(&ui->ui_mutex); generic_fillattr(inode, stat); stat->blksize = UBIFS_BLOCK_SIZE; stat->size = ui->ui_size; /* * 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; } const struct inode_operations ubifs_dir_inode_operations = { .lookup = ubifs_lookup, .create = ubifs_create, .link = ubifs_link, .symlink = ubifs_symlink, .unlink = ubifs_unlink, .mkdir = ubifs_mkdir, .rmdir = ubifs_rmdir, .mknod = ubifs_mknod, .rename = ubifs_rename, .setattr = ubifs_setattr, .getattr = ubifs_getattr, .setxattr = ubifs_setxattr, .getxattr = ubifs_getxattr, .listxattr = ubifs_listxattr, .removexattr = ubifs_removexattr, }; const struct file_operations ubifs_dir_operations = { .llseek = generic_file_llseek, .release = ubifs_dir_release, .read = generic_read_dir, .iterate = ubifs_readdir, .fsync = ubifs_fsync, .unlocked_ioctl = ubifs_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif };
static int ubifs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(old_dentry); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change = CALC_DENT_SIZE(dentry->d_name.len); struct ubifs_budget_req req = { .new_dent = 1, .dirtied_ino = 2, .dirtied_ino_d = ALIGN(ui->data_len, 8) }; struct fscrypt_name nm; /* * Budget request settings: new direntry, changing the target inode, * changing the parent inode. */ dbg_gen("dent '%pd' to ino %lu (nlink %d) in dir ino %lu", dentry, inode->i_ino, inode->i_nlink, dir->i_ino); ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(inode)); if (ubifs_crypt_is_encrypted(dir) && !fscrypt_has_permitted_context(dir, inode)) return -EPERM; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) return err; err = dbg_check_synced_i_size(c, inode); if (err) goto out_fname; err = ubifs_budget_space(c, &req); if (err) goto out_fname; lock_2_inodes(dir, inode); /* Handle O_TMPFILE corner case, it is allowed to link a O_TMPFILE. */ if (inode->i_nlink == 0) ubifs_delete_orphan(c, inode->i_ino); inc_nlink(inode); ihold(inode); inode->i_ctime = current_time(inode); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(inode); if (inode->i_nlink == 0) ubifs_add_orphan(c, inode->i_ino); unlock_2_inodes(dir, inode); ubifs_release_budget(c, &req); iput(inode); out_fname: fscrypt_free_filename(&nm); return err; } static int ubifs_unlink(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(dentry); struct ubifs_inode *dir_ui = ubifs_inode(dir); int err, sz_change, budgeted = 1; struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; unsigned int saved_nlink = inode->i_nlink; struct fscrypt_name nm; /* * 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); if (ubifs_crypt_is_encrypted(dir)) { err = fscrypt_get_encryption_info(dir); if (err && err != -ENOKEY) return err; } err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); if (err) return err; sz_change = CALC_DENT_SIZE(fname_len(&nm)); ubifs_assert(inode_is_locked(dir)); ubifs_assert(inode_is_locked(inode)); err = dbg_check_synced_i_size(c, inode); if (err) goto out_fname; err = ubifs_budget_space(c, &req); if (err) { if (err != -ENOSPC) goto out_fname; budgeted = 0; } lock_2_inodes(dir, inode); inode->i_ctime = current_time(dir); drop_nlink(inode); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; set_nlink(inode, saved_nlink); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); out_fname: fscrypt_free_filename(&nm); return err; } /** * 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 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; lowest_dent_key(c, &key, dir->i_ino); dent = ubifs_tnc_next_ent(c, &key, &nm); if (IS_ERR(dent)) { err = PTR_ERR(dent); if (err == -ENOENT) err = 0; } else { kfree(dent); err = -ENOTEMPTY; } return err; } static int ubifs_rmdir(struct inode *dir, struct dentry *dentry) { struct ubifs_info *c = dir->i_sb->s_fs_info; struct inode *inode = d_inode(dentry); int err, sz_change, budgeted = 1; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 }; struct fscrypt_name nm; /* * 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(inode_is_locked(dir)); ubifs_assert(inode_is_locked(inode)); err = ubifs_check_dir_empty(d_inode(dentry)); if (err) return err; if (ubifs_crypt_is_encrypted(dir)) { err = fscrypt_get_encryption_info(dir); if (err && err != -ENOKEY) return err; } err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm); 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; } lock_2_inodes(dir, inode); inode->i_ctime = current_time(dir); clear_nlink(inode); drop_nlink(dir); dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0); if (err) goto out_cancel; unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); else { /* We've deleted something - clean the "no space" flags */ c->bi.nospace = c->bi.nospace_rp = 0; smp_wmb(); } fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; inc_nlink(dir); set_nlink(inode, 2); unlock_2_inodes(dir, inode); if (budgeted) ubifs_release_budget(c, &req); out_fname: fscrypt_free_filename(&nm); return err; } static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, sz_change; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1 }; struct fscrypt_name nm; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd', mode %#hx in dir ino %lu", dentry, mode, dir->i_ino); err = ubifs_budget_space(c, &req); if (err) return err; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) goto out_budg; sz_change = CALC_DENT_SIZE(fname_len(&nm)); inode = ubifs_new_inode(c, dir, S_IFDIR | mode); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_fname; } err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); insert_inode_hash(inode); inc_nlink(inode); inc_nlink(dir); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) { ubifs_err(c, "cannot create directory, error %d", err); goto out_cancel; } mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; drop_nlink(dir); mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_fname: fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; union ubifs_dev_desc *dev = NULL; int sz_change; int err, devlen = 0; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .dirtied_ino = 1 }; struct fscrypt_name nm; /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino); if (S_ISBLK(mode) || S_ISCHR(mode)) { dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); if (!dev) return -ENOMEM; devlen = ubifs_encode_dev(dev, rdev); } req.new_ino_d = ALIGN(devlen, 8); err = ubifs_budget_space(c, &req); if (err) { kfree(dev); return err; } err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) { kfree(dev); goto out_budg; } sz_change = CALC_DENT_SIZE(fname_len(&nm)); inode = ubifs_new_inode(c, dir, mode); if (IS_ERR(inode)) { kfree(dev); err = PTR_ERR(inode); goto out_fname; } init_special_inode(inode, inode->i_mode, rdev); inode->i_size = ubifs_inode(inode)->ui_size = devlen; ui = ubifs_inode(inode); ui->data = dev; ui->data_len = devlen; err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_fname: fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); return err; } static int ubifs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct inode *inode; struct ubifs_inode *ui; struct ubifs_inode *dir_ui = ubifs_inode(dir); struct ubifs_info *c = dir->i_sb->s_fs_info; int err, len = strlen(symname); int sz_change = CALC_DENT_SIZE(len); struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); struct fscrypt_symlink_data *sd = NULL; struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, .new_ino_d = ALIGN(len, 8), .dirtied_ino = 1 }; struct fscrypt_name nm; if (ubifs_crypt_is_encrypted(dir)) { err = fscrypt_get_encryption_info(dir); if (err) goto out_budg; if (!fscrypt_has_encryption_key(dir)) { err = -EPERM; goto out_budg; } disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + sizeof(struct fscrypt_symlink_data)); } /* * Budget request settings: new inode, new direntry and changing parent * directory inode. */ dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, symname, dir->i_ino); if (disk_link.len > UBIFS_MAX_INO_DATA) return -ENAMETOOLONG; err = ubifs_budget_space(c, &req); if (err) return err; err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm); if (err) goto out_budg; inode = ubifs_new_inode(c, dir, S_IFLNK | S_IRWXUGO); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_fname; } ui = ubifs_inode(inode); ui->data = kmalloc(disk_link.len, GFP_NOFS); if (!ui->data) { err = -ENOMEM; goto out_inode; } if (ubifs_crypt_is_encrypted(dir)) { struct qstr istr = QSTR_INIT(symname, len); struct fscrypt_str ostr; sd = kzalloc(disk_link.len, GFP_NOFS); if (!sd) { err = -ENOMEM; goto out_inode; } ostr.name = sd->encrypted_path; ostr.len = disk_link.len; err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); if (err) { kfree(sd); goto out_inode; } sd->len = cpu_to_le16(ostr.len); disk_link.name = (char *)sd; } else { inode->i_link = ui->data; } memcpy(ui->data, disk_link.name, disk_link.len); ((char *)ui->data)[disk_link.len - 1] = '\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 @len, not @len + %1. */ ui->data_len = disk_link.len - 1; inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; err = ubifs_init_security(dir, inode, &dentry->d_name); if (err) goto out_inode; mutex_lock(&dir_ui->ui_mutex); dir->i_size += sz_change; dir_ui->ui_size = dir->i_size; dir->i_mtime = dir->i_ctime = inode->i_ctime; err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0); if (err) goto out_cancel; mutex_unlock(&dir_ui->ui_mutex); ubifs_release_budget(c, &req); insert_inode_hash(inode); d_instantiate(dentry, inode); fscrypt_free_filename(&nm); return 0; out_cancel: dir->i_size -= sz_change; dir_ui->ui_size = dir->i_size; mutex_unlock(&dir_ui->ui_mutex); out_inode: make_bad_inode(inode); iput(inode); out_fname: fscrypt_free_filename(&nm); out_budg: ubifs_release_budget(c, &req); return err; } /** * lock_4_inodes - a wrapper for locking three UBIFS inodes. * @inode1: first inode * @inode2: second inode * @inode3: third inode * @inode4: fouth 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. */ static void 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: fouth inode */ static void 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); } static int do_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct inode *old_inode = d_inode(old_dentry); struct inode *new_inode = d_inode(new_dentry); struct inode *whiteout = NULL; struct ubifs_inode *old_inode_ui = ubifs_inode(old_inode); struct ubifs_inode *whiteout_ui = NULL; int err, release, sync = 0, move = (new_dir != old_dir); int is_dir = S_ISDIR(old_inode->i_mode); int unlink = !!new_inode, new_sz, old_sz; struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 3 }; struct ubifs_budget_req ino_req = { .dirtied_ino = 1, .dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) }; struct timespec time; unsigned int uninitialized_var(saved_nlink); struct fscrypt_name old_nm, new_nm; /* * Budget request settings: deletion direntry, new direntry, removing * the old inode, and changing old and new parent directory inodes. * * However, this operation also marks the target inode as dirty and * does not write it, so we allocate budget for the target inode * separately. */ 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(inode_is_locked(new_inode)); if (old_dir != new_dir) { if (ubifs_crypt_is_encrypted(new_dir) && !fscrypt_has_permitted_context(new_dir, old_inode)) return -EPERM; } 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; err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &new_nm); if (err) { fscrypt_free_filename(&old_nm); return err; } new_sz = CALC_DENT_SIZE(fname_len(&new_nm)); old_sz = CALC_DENT_SIZE(fname_len(&old_nm)); err = ubifs_budget_space(c, &req); if (err) { fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); return err; } err = ubifs_budget_space(c, &ino_req); if (err) { fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); ubifs_release_budget(c, &req); 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; } err = do_tmpfile(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE, &whiteout); if (err) { kfree(dev); goto out_release; } whiteout->i_state |= I_LINKABLE; whiteout_ui = ubifs_inode(whiteout); whiteout_ui->data = dev; whiteout_ui->data_len = ubifs_encode_dev(dev, MKDEV(0, 0)); ubifs_assert(!whiteout_ui->dirty); } lock_4_inodes(old_dir, new_dir, new_inode, whiteout); /* * Like most other Unix systems, set the @i_ctime for inodes on a * rename. */ time = current_time(old_dir); old_inode->i_ctime = time; /* 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); } } old_dir->i_size -= old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; /* * 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 and change its ctime. */ 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); new_inode->i_ctime = time; } 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; } if (whiteout) { struct ubifs_budget_req wht_req = { .dirtied_ino = 1, .dirtied_ino_d = \ ALIGN(ubifs_inode(whiteout)->data_len, 8) }; err = ubifs_budget_space(c, &wht_req); if (err) { kfree(whiteout_ui->data); whiteout_ui->data_len = 0; iput(whiteout); goto out_release; } inc_nlink(whiteout); mark_inode_dirty(whiteout); whiteout->i_state &= ~I_LINKABLE; iput(whiteout); } err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir, new_inode, &new_nm, whiteout, sync); if (err) goto out_cancel; unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); ubifs_release_budget(c, &req); mutex_lock(&old_inode_ui->ui_mutex); release = old_inode_ui->dirty; mark_inode_dirty_sync(old_inode); mutex_unlock(&old_inode_ui->ui_mutex); if (release) ubifs_release_budget(c, &ino_req); if (IS_SYNC(old_inode)) err = old_inode->i_sb->s_op->write_inode(old_inode, NULL); fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); return err; out_cancel: if (unlink) { set_nlink(new_inode, saved_nlink); } else { new_dir->i_size -= new_sz; ubifs_inode(new_dir)->ui_size = new_dir->i_size; } old_dir->i_size += old_sz; ubifs_inode(old_dir)->ui_size = old_dir->i_size; if (is_dir) { if (move) { inc_nlink(old_dir); if (!unlink) drop_nlink(new_dir); } else { if (unlink) inc_nlink(old_dir); } } if (whiteout) { drop_nlink(whiteout); iput(whiteout); } unlock_4_inodes(old_dir, new_dir, new_inode, whiteout); out_release: ubifs_release_budget(c, &ino_req); ubifs_release_budget(c, &req); fscrypt_free_filename(&old_nm); fscrypt_free_filename(&new_nm); return err; } static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { struct ubifs_info *c = old_dir->i_sb->s_fs_info; struct ubifs_budget_req req = { .new_dent = 1, .mod_dent = 1, .dirtied_ino = 2 }; int sync = IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir); struct inode *fst_inode = d_inode(old_dentry); struct inode *snd_inode = d_inode(new_dentry); struct timespec time; int err; struct fscrypt_name fst_nm, snd_nm; ubifs_assert(fst_inode && snd_inode); if ((ubifs_crypt_is_encrypted(old_dir) || ubifs_crypt_is_encrypted(new_dir)) && (old_dir != new_dir) && (!fscrypt_has_permitted_context(new_dir, fst_inode) || !fscrypt_has_permitted_context(old_dir, snd_inode))) return -EPERM; err = fscrypt_setup_filename(old_dir, &old_dentry->d_name, 0, &fst_nm); if (err) return err; err = fscrypt_setup_filename(new_dir, &new_dentry->d_name, 0, &snd_nm); if (err) { fscrypt_free_filename(&fst_nm); return err; } lock_4_inodes(old_dir, new_dir, NULL, NULL); time = current_time(old_dir); fst_inode->i_ctime = time; snd_inode->i_ctime = time; old_dir->i_mtime = old_dir->i_ctime = time; new_dir->i_mtime = new_dir->i_ctime = time; if (old_dir != new_dir) { if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) { inc_nlink(new_dir); drop_nlink(old_dir); } else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) { drop_nlink(new_dir); inc_nlink(old_dir); } } err = ubifs_jnl_xrename(c, old_dir, fst_inode, &fst_nm, new_dir, snd_inode, &snd_nm, sync); unlock_4_inodes(old_dir, new_dir, NULL, NULL); ubifs_release_budget(c, &req); fscrypt_free_filename(&fst_nm); fscrypt_free_filename(&snd_nm); return err; } static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) { if (flags & ~(RENAME_NOREPLACE | RENAME_WHITEOUT | RENAME_EXCHANGE)) return -EINVAL; ubifs_assert(inode_is_locked(old_dir)); ubifs_assert(inode_is_locked(new_dir)); if (flags & RENAME_EXCHANGE) return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry); return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags); } int ubifs_getattr(const struct path *path, struct kstat *stat, u32 request_mask, unsigned int flags) { loff_t size; struct inode *inode = d_inode(path->dentry); struct ubifs_inode *ui = ubifs_inode(inode); mutex_lock(&ui->ui_mutex); if (ui->flags & UBIFS_APPEND_FL) stat->attributes |= STATX_ATTR_APPEND; if (ui->flags & UBIFS_COMPR_FL) stat->attributes |= STATX_ATTR_COMPRESSED; if (ui->flags & UBIFS_CRYPT_FL) stat->attributes |= STATX_ATTR_ENCRYPTED; if (ui->flags & UBIFS_IMMUTABLE_FL) stat->attributes |= STATX_ATTR_IMMUTABLE; stat->attributes_mask |= (STATX_ATTR_APPEND | STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED | STATX_ATTR_IMMUTABLE); generic_fillattr(inode, stat); stat->blksize = UBIFS_BLOCK_SIZE; stat->size = ui->ui_size; /* * 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; } static int ubifs_dir_open(struct inode *dir, struct file *file) { if (ubifs_crypt_is_encrypted(dir)) return fscrypt_get_encryption_info(dir) ? -EACCES : 0; return 0; } const struct inode_operations ubifs_dir_inode_operations = { .lookup = ubifs_lookup, .create = ubifs_create, .link = ubifs_link, .symlink = ubifs_symlink, .unlink = ubifs_unlink, .mkdir = ubifs_mkdir, .rmdir = ubifs_rmdir, .mknod = ubifs_mknod, .rename = ubifs_rename, .setattr = ubifs_setattr, .getattr = ubifs_getattr, .listxattr = ubifs_listxattr, #ifdef CONFIG_UBIFS_ATIME_SUPPORT .update_time = ubifs_update_time, #endif .tmpfile = ubifs_tmpfile, }; const struct file_operations ubifs_dir_operations = { .llseek = generic_file_llseek, .release = ubifs_dir_release, .read = generic_read_dir, .iterate_shared = ubifs_readdir, .fsync = ubifs_fsync, .unlocked_ioctl = ubifs_ioctl, .open = ubifs_dir_open, #ifdef CONFIG_COMPAT .compat_ioctl = ubifs_compat_ioctl, #endif };