mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 00:34:20 +08:00
This pull request contains:
* File encryption for UBIFS using the fscrypt framework * A fix to honor the dirty_writeback_interval sysctl * Removal of dead code -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJYUrkeAAoJEEtJtSqsAOnWlOYP/jdf3jljSDZZUbLAxZDzpYWx lS86+Koht8n/FcOu2JLZJalwCxXDkqe09cNg7anGAT3pPnbrJbOCpKNj5V5CAxfX I6rNiKhNFwtcVfH9Snv0O5qIfxk+uNxApGkULLE+bqpNdSYsjGxeI+f/7TARa3UU QOlP3UM2dVcqwCUpjJDojVQ3rFnKR91J8KNkBbcq1Yzg5DuiyZowMYBuXSzxVGJ5 wAP3VNPd38s9/PlFvr+sHaLOdCp5GOtT5WrkCidFR8wqzCWtKgoU+w5alz6jz8XN uJ/5J9qw1SPotZs6vqRCTll+eGLheVhpkpFRnPosHL1DhS9OrH1T9OZUWgZrfUGM eEYhEwvwYwZiywsNUa5Evh1I6jMLvgH3xP/61/BO6xRYOyXa7hkb9y7SEKUm402t fUF2V91e8ndNGUp879hgOBuHhQebjW6IIY2j6KFzRQgnswDkKN5Vbjd57/kTFC6m JvrUE/mNDj7zHAG07JShnVyDGkmV71kD3Ixrr99L1DqJaiOoTzc8Vqch6y5wcdwy GRB4580z3YgdoLNi7VxZi79Qpz1DkEMNI8B30yhnQF2zwpuDwkj9lJS/DKRurA+W OW/DPZjuSG3kLApErfwjzfcTpbOzX3App+fx3lwvsTXt/qqEDxOuo16NrSJE5PK5 gjviqfL4UMwY6FkVlJDB =xBCi -----END PGP SIGNATURE----- Merge tag 'upstream-4.10-rc1' of git://git.infradead.org/linux-ubifs Pull ubifs updates from Richard Weinberger: - file encryption for UBIFS using the fscrypt framework - a fix to honor the dirty_writeback_interval sysctl - removal of dead code * tag 'upstream-4.10-rc1' of git://git.infradead.org/linux-ubifs: (30 commits) ubifs: Initialize fstr_real_len ubifs: Use fscrypt ioctl() helpers ubifs: Use FS_CFLG_OWN_PAGES ubifs: Raise write version to 5 ubifs: Implement UBIFS_FLG_ENCRYPTION ubifs: Implement UBIFS_FLG_DOUBLE_HASH ubifs: Use a random number for cookies ubifs: Add full hash lookup support ubifs: Rename tnc_read_node_nm ubifs: Add support for encrypted symlinks ubifs: Implement encrypted filenames ubifs: Make r5 hash binary string aware ubifs: Relax checks in ubifs_validate_entry() ubifs: Implement encrypt/decrypt for all IO ubifs: Constify struct inode pointer in ubifs_crypt_is_encrypted() ubifs: Introduce new data node field, compr_size ubifs: Enforce crypto policy in mmap ubifs: Massage assert in ubifs_xattr_set() wrt. fscrypto ubifs: Preload crypto context in ->lookup() ubifs: Enforce crypto policy in ->link and ->rename ...
This commit is contained in:
commit
39d2c3b96e
@ -50,3 +50,14 @@ config UBIFS_ATIME_SUPPORT
|
||||
strictatime is the "heavy", relatime is "lighter", etc.
|
||||
|
||||
If unsure, say 'N'
|
||||
|
||||
config UBIFS_FS_ENCRYPTION
|
||||
bool "UBIFS Encryption"
|
||||
depends on UBIFS_FS
|
||||
select FS_ENCRYPTION
|
||||
default n
|
||||
help
|
||||
Enable encryption of UBIFS files and directories. This
|
||||
feature is similar to ecryptfs, but it is more memory
|
||||
efficient since it avoids caching the encrypted and
|
||||
decrypted pages in the page cache.
|
||||
|
@ -5,3 +5,4 @@ ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
|
||||
ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
|
||||
ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
|
||||
ubifs-y += misc.o
|
||||
ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o
|
||||
|
97
fs/ubifs/crypto.c
Normal file
97
fs/ubifs/crypto.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include "ubifs.h"
|
||||
|
||||
static int ubifs_crypt_get_context(struct inode *inode, void *ctx, size_t len)
|
||||
{
|
||||
return ubifs_xattr_get(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
|
||||
ctx, len);
|
||||
}
|
||||
|
||||
static int ubifs_crypt_set_context(struct inode *inode, const void *ctx,
|
||||
size_t len, void *fs_data)
|
||||
{
|
||||
return ubifs_xattr_set(inode, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT,
|
||||
ctx, len, 0);
|
||||
}
|
||||
|
||||
static bool ubifs_crypt_empty_dir(struct inode *inode)
|
||||
{
|
||||
return ubifs_check_dir_empty(inode) == 0;
|
||||
}
|
||||
|
||||
static unsigned int ubifs_crypt_max_namelen(struct inode *inode)
|
||||
{
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
return UBIFS_MAX_INO_DATA;
|
||||
else
|
||||
return UBIFS_MAX_NLEN;
|
||||
}
|
||||
|
||||
static int ubifs_key_prefix(struct inode *inode, u8 **key)
|
||||
{
|
||||
static char prefix[] = "ubifs:";
|
||||
|
||||
*key = prefix;
|
||||
|
||||
return sizeof(prefix) - 1;
|
||||
}
|
||||
|
||||
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
unsigned int in_len, unsigned int *out_len, int block)
|
||||
{
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
void *p = &dn->data;
|
||||
struct page *ret;
|
||||
unsigned int pad_len = round_up(in_len, UBIFS_CIPHER_BLOCK_SIZE);
|
||||
|
||||
ubifs_assert(pad_len <= *out_len);
|
||||
dn->compr_size = cpu_to_le16(in_len);
|
||||
|
||||
/* pad to full block cipher length */
|
||||
if (pad_len != in_len)
|
||||
memset(p + in_len, 0, pad_len - in_len);
|
||||
|
||||
ret = fscrypt_encrypt_page(inode, virt_to_page(&dn->data), pad_len,
|
||||
offset_in_page(&dn->data), block, GFP_NOFS);
|
||||
if (IS_ERR(ret)) {
|
||||
ubifs_err(c, "fscrypt_encrypt_page failed: %ld", PTR_ERR(ret));
|
||||
return PTR_ERR(ret);
|
||||
}
|
||||
*out_len = pad_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
unsigned int *out_len, int block)
|
||||
{
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
int err;
|
||||
unsigned int clen = le16_to_cpu(dn->compr_size);
|
||||
unsigned int dlen = *out_len;
|
||||
|
||||
if (clen <= 0 || clen > UBIFS_BLOCK_SIZE || clen > dlen) {
|
||||
ubifs_err(c, "bad compr_size: %i", clen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ubifs_assert(dlen <= UBIFS_BLOCK_SIZE);
|
||||
err = fscrypt_decrypt_page(inode, virt_to_page(&dn->data), dlen,
|
||||
offset_in_page(&dn->data), block);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_decrypt_page failed: %i", err);
|
||||
return err;
|
||||
}
|
||||
*out_len = clen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct fscrypt_operations ubifs_crypt_operations = {
|
||||
.flags = FS_CFLG_OWN_PAGES,
|
||||
.get_context = ubifs_crypt_get_context,
|
||||
.set_context = ubifs_crypt_set_context,
|
||||
.is_encrypted = __ubifs_crypt_is_encrypted,
|
||||
.empty_dir = ubifs_crypt_empty_dir,
|
||||
.max_namelen = ubifs_crypt_max_namelen,
|
||||
.key_prefix = ubifs_key_prefix,
|
||||
};
|
@ -233,7 +233,7 @@ static void dump_ch(const struct ubifs_ch *ch)
|
||||
void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
{
|
||||
const struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
struct qstr nm = { .name = NULL };
|
||||
struct fscrypt_name nm = {0};
|
||||
union ubifs_key key;
|
||||
struct ubifs_dent_node *dent, *pdent = NULL;
|
||||
int count = 2;
|
||||
@ -289,8 +289,8 @@ void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
pr_err("\t%d: %s (%s)\n",
|
||||
count++, dent->name, get_dent_type(dent->type));
|
||||
|
||||
nm.name = dent->name;
|
||||
nm.len = le16_to_cpu(dent->nlen);
|
||||
fname_name(&nm) = dent->name;
|
||||
fname_len(&nm) = le16_to_cpu(dent->nlen);
|
||||
kfree(pdent);
|
||||
pdent = dent;
|
||||
key_read(c, &dent->key, &key);
|
||||
@ -1107,7 +1107,7 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
|
||||
unsigned int nlink = 2;
|
||||
union ubifs_key key;
|
||||
struct ubifs_dent_node *dent, *pdent = NULL;
|
||||
struct qstr nm = { .name = NULL };
|
||||
struct fscrypt_name nm = {0};
|
||||
loff_t size = UBIFS_INO_NODE_SZ;
|
||||
|
||||
if (!dbg_is_chk_gen(c))
|
||||
@ -1128,9 +1128,9 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
|
||||
return err;
|
||||
}
|
||||
|
||||
nm.name = dent->name;
|
||||
nm.len = le16_to_cpu(dent->nlen);
|
||||
size += CALC_DENT_SIZE(nm.len);
|
||||
fname_name(&nm) = dent->name;
|
||||
fname_len(&nm) = le16_to_cpu(dent->nlen);
|
||||
size += CALC_DENT_SIZE(fname_len(&nm));
|
||||
if (dent->type == UBIFS_ITYPE_DIR)
|
||||
nlink += 1;
|
||||
kfree(pdent);
|
||||
|
476
fs/ubifs/dir.c
476
fs/ubifs/dir.c
@ -85,11 +85,26 @@ static int inherit_flags(const struct inode *dir, umode_t mode)
|
||||
* initializes it. Returns new inode in case of success and an error code in
|
||||
* case of failure.
|
||||
*/
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
umode_t mode)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
struct ubifs_inode *ui;
|
||||
bool encrypted = false;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_get_encryption_info failed: %i", err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
if (!fscrypt_has_encryption_key(dir))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
encrypted = true;
|
||||
}
|
||||
|
||||
inode = new_inode(c->vfs_sb);
|
||||
ui = ubifs_inode(inode);
|
||||
@ -165,18 +180,29 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
|
||||
*/
|
||||
ui->creat_sqnum = ++c->max_sqnum;
|
||||
spin_unlock(&c->cnt_lock);
|
||||
|
||||
if (encrypted) {
|
||||
err = fscrypt_inherit_context(dir, inode, &encrypted, true);
|
||||
if (err) {
|
||||
ubifs_err(c, "fscrypt_inherit_context failed: %i", err);
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
}
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
static int dbg_check_name(const struct ubifs_info *c,
|
||||
const struct ubifs_dent_node *dent,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
if (!dbg_is_chk_gen(c))
|
||||
return 0;
|
||||
if (le16_to_cpu(dent->nlen) != nm->len)
|
||||
if (le16_to_cpu(dent->nlen) != fname_len(nm))
|
||||
return -EINVAL;
|
||||
if (memcmp(dent->name, nm->name, nm->len))
|
||||
if (memcmp(dent->name, fname_name(nm), fname_len(nm)))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@ -189,30 +215,61 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct inode *inode = NULL;
|
||||
struct ubifs_dent_node *dent;
|
||||
struct ubifs_info *c = dir->i_sb->s_fs_info;
|
||||
struct fscrypt_name nm;
|
||||
|
||||
dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
|
||||
|
||||
if (dentry->d_name.len > UBIFS_MAX_NLEN)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
|
||||
/*
|
||||
* DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is
|
||||
* created while the directory was encrypted and we
|
||||
* have access to the key.
|
||||
*/
|
||||
if (fscrypt_has_encryption_key(dir))
|
||||
fscrypt_set_encrypted_dentry(dentry);
|
||||
fscrypt_set_d_op(dentry);
|
||||
if (err && err != -ENOKEY)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
if (fname_len(&nm) > UBIFS_MAX_NLEN) {
|
||||
err = -ENAMETOOLONG;
|
||||
goto out_fname;
|
||||
}
|
||||
|
||||
dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
|
||||
if (!dent)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!dent) {
|
||||
err = -ENOMEM;
|
||||
goto out_fname;
|
||||
}
|
||||
|
||||
dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
|
||||
if (nm.hash) {
|
||||
ubifs_assert(fname_len(&nm) == 0);
|
||||
ubifs_assert(fname_name(&nm) == NULL);
|
||||
dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
|
||||
err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
|
||||
} else {
|
||||
dent_key_init(c, &key, dir->i_ino, &nm);
|
||||
err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
|
||||
}
|
||||
|
||||
err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
|
||||
if (err) {
|
||||
if (err == -ENOENT) {
|
||||
dbg_gen("not found");
|
||||
goto done;
|
||||
}
|
||||
goto out;
|
||||
goto out_dent;
|
||||
}
|
||||
|
||||
if (dbg_check_name(c, dent, &dentry->d_name)) {
|
||||
if (dbg_check_name(c, dent, &nm)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
goto out_dent;
|
||||
}
|
||||
|
||||
inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
|
||||
@ -225,11 +282,12 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
ubifs_err(c, "dead directory entry '%pd', error %d",
|
||||
dentry, err);
|
||||
ubifs_ro_mode(c, err);
|
||||
goto out;
|
||||
goto out_dent;
|
||||
}
|
||||
|
||||
done:
|
||||
kfree(dent);
|
||||
fscrypt_free_filename(&nm);
|
||||
/*
|
||||
* Note, d_splice_alias() would be required instead if we supported
|
||||
* NFS.
|
||||
@ -237,8 +295,10 @@ done:
|
||||
d_add(dentry, inode);
|
||||
return NULL;
|
||||
|
||||
out:
|
||||
out_dent:
|
||||
kfree(dent);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
@ -247,10 +307,11 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
{
|
||||
struct inode *inode;
|
||||
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,
|
||||
.dirtied_ino = 1 };
|
||||
struct ubifs_inode *dir_ui = ubifs_inode(dir);
|
||||
struct fscrypt_name nm;
|
||||
int err, sz_change;
|
||||
|
||||
/*
|
||||
* Budget request settings: new inode, new direntry, changing the
|
||||
@ -264,10 +325,16 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
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, mode);
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
goto out_budg;
|
||||
goto out_fname;
|
||||
}
|
||||
|
||||
err = ubifs_init_security(dir, inode, &dentry->d_name);
|
||||
@ -278,12 +345,13 @@ static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
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);
|
||||
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);
|
||||
fscrypt_free_filename(&nm);
|
||||
insert_inode_hash(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
@ -295,6 +363,8 @@ out_cancel:
|
||||
out_inode:
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
out_budg:
|
||||
ubifs_release_budget(c, &req);
|
||||
ubifs_err(c, "cannot create regular file, error %d", err);
|
||||
@ -310,6 +380,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
struct ubifs_budget_req ino_req = { .dirtied_ino = 1 };
|
||||
struct ubifs_inode *ui, *dir_ui = ubifs_inode(dir);
|
||||
int err, instantiated = 0;
|
||||
struct fscrypt_name nm;
|
||||
|
||||
/*
|
||||
* Budget request settings: new dirty inode, new direntry,
|
||||
@ -319,13 +390,30 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
|
||||
dentry, mode, dir->i_ino);
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!fscrypt_has_encryption_key(dir)) {
|
||||
return -EPERM;
|
||||
}
|
||||
}
|
||||
|
||||
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
if (err) {
|
||||
fscrypt_free_filename(&nm);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ubifs_budget_space(c, &ino_req);
|
||||
if (err) {
|
||||
ubifs_release_budget(c, &req);
|
||||
fscrypt_free_filename(&nm);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -361,7 +449,7 @@ static int do_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
mutex_unlock(&ui->ui_mutex);
|
||||
|
||||
mutex_lock(&dir_ui->ui_mutex);
|
||||
err = ubifs_jnl_update(c, dir, &dentry->d_name, inode, 1, 0);
|
||||
err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
mutex_unlock(&dir_ui->ui_mutex);
|
||||
@ -380,6 +468,7 @@ out_budg:
|
||||
ubifs_release_budget(c, &req);
|
||||
if (!instantiated)
|
||||
ubifs_release_budget(c, &ino_req);
|
||||
fscrypt_free_filename(&nm);
|
||||
ubifs_err(c, "cannot create temporary file, error %d", err);
|
||||
return err;
|
||||
}
|
||||
@ -439,12 +528,14 @@ static unsigned int vfs_dent_type(uint8_t type)
|
||||
*/
|
||||
static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
int err = 0;
|
||||
struct qstr nm;
|
||||
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 = ubifs_crypt_is_encrypted(dir);
|
||||
|
||||
dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
|
||||
|
||||
@ -455,6 +546,18 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
*/
|
||||
return 0;
|
||||
|
||||
if (encrypted) {
|
||||
err = fscrypt_get_encryption_info(dir);
|
||||
if (err && err != -ENOKEY)
|
||||
return err;
|
||||
|
||||
err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fstr_real_len = fstr.len;
|
||||
}
|
||||
|
||||
if (file->f_version == 0) {
|
||||
/*
|
||||
* The file was seek'ed, which means that @file->private_data
|
||||
@ -476,12 +579,15 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
/* File positions 0 and 1 correspond to "." and ".." */
|
||||
if (ctx->pos < 2) {
|
||||
ubifs_assert(!file->private_data);
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
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);
|
||||
nm.name = NULL;
|
||||
fname_len(&nm) = 0;
|
||||
dent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
if (IS_ERR(dent)) {
|
||||
err = PTR_ERR(dent);
|
||||
@ -499,7 +605,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
* Find the entry corresponding to @ctx->pos or the closest one.
|
||||
*/
|
||||
dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
|
||||
nm.name = NULL;
|
||||
fname_len(&nm) = 0;
|
||||
dent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
if (IS_ERR(dent)) {
|
||||
err = PTR_ERR(dent);
|
||||
@ -516,15 +622,33 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
|
||||
ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
|
||||
ubifs_inode(dir)->creat_sqnum);
|
||||
|
||||
nm.len = le16_to_cpu(dent->nlen);
|
||||
if (!dir_emit(ctx, dent->name, nm.len,
|
||||
fname_len(&nm) = le16_to_cpu(dent->nlen);
|
||||
fname_name(&nm) = dent->name;
|
||||
|
||||
if (encrypted) {
|
||||
fstr.len = fstr_real_len;
|
||||
|
||||
err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
|
||||
&dent->key),
|
||||
le32_to_cpu(dent->cookie),
|
||||
&nm.disk_name, &fstr);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
fstr.len = fname_len(&nm);
|
||||
fstr.name = fname_name(&nm);
|
||||
}
|
||||
|
||||
if (!dir_emit(ctx, fstr.name, fstr.len,
|
||||
le64_to_cpu(dent->inum),
|
||||
vfs_dent_type(dent->type)))
|
||||
vfs_dent_type(dent->type))) {
|
||||
if (encrypted)
|
||||
fscrypt_fname_free_buffer(&fstr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Switch to the next entry */
|
||||
key_read(c, &dent->key, &key);
|
||||
nm.name = dent->name;
|
||||
dent = ubifs_tnc_next_ent(c, &key, &nm);
|
||||
if (IS_ERR(dent)) {
|
||||
err = PTR_ERR(dent);
|
||||
@ -541,6 +665,9 @@ out:
|
||||
kfree(file->private_data);
|
||||
file->private_data = NULL;
|
||||
|
||||
if (encrypted)
|
||||
fscrypt_fname_free_buffer(&fstr);
|
||||
|
||||
if (err != -ENOENT)
|
||||
ubifs_err(c, "cannot find next direntry, error %d", err);
|
||||
else
|
||||
@ -601,6 +728,7 @@ static int ubifs_link(struct dentry *old_dentry, struct 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,
|
||||
@ -613,14 +741,30 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
ubifs_assert(inode_is_locked(dir));
|
||||
ubifs_assert(inode_is_locked(inode));
|
||||
|
||||
err = dbg_check_synced_i_size(c, inode);
|
||||
if (ubifs_crypt_is_encrypted(dir)) {
|
||||
if (!fscrypt_has_permitted_context(dir, inode))
|
||||
return -EPERM;
|
||||
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
if (!fscrypt_has_encryption_key(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);
|
||||
inc_nlink(inode);
|
||||
ihold(inode);
|
||||
@ -628,13 +772,14 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *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);
|
||||
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:
|
||||
@ -644,6 +789,8 @@ out_cancel:
|
||||
unlock_2_inodes(dir, inode);
|
||||
ubifs_release_budget(c, &req);
|
||||
iput(inode);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -652,10 +799,10 @@ 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;
|
||||
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
|
||||
@ -667,16 +814,29 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
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)
|
||||
return err;
|
||||
goto out_fname;
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
if (err) {
|
||||
if (err != -ENOSPC)
|
||||
return err;
|
||||
goto out_fname;
|
||||
budgeted = 0;
|
||||
}
|
||||
|
||||
@ -686,7 +846,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
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);
|
||||
err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
unlock_2_inodes(dir, inode);
|
||||
@ -698,6 +858,7 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
c->bi.nospace = c->bi.nospace_rp = 0;
|
||||
smp_wmb();
|
||||
}
|
||||
fscrypt_free_filename(&nm);
|
||||
return 0;
|
||||
|
||||
out_cancel:
|
||||
@ -707,21 +868,23 @@ out_cancel:
|
||||
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.
|
||||
* @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)
|
||||
int ubifs_check_dir_empty(struct inode *dir)
|
||||
{
|
||||
struct qstr nm = { .name = NULL };
|
||||
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;
|
||||
@ -743,10 +906,10 @@ 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;
|
||||
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
|
||||
@ -758,14 +921,26 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
inode->i_ino, dir->i_ino);
|
||||
ubifs_assert(inode_is_locked(dir));
|
||||
ubifs_assert(inode_is_locked(inode));
|
||||
err = check_dir_empty(c, d_inode(dentry));
|
||||
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)
|
||||
return err;
|
||||
goto out_fname;
|
||||
budgeted = 0;
|
||||
}
|
||||
|
||||
@ -776,7 +951,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
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);
|
||||
err = ubifs_jnl_update(c, dir, &nm, inode, 1, 0);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
unlock_2_inodes(dir, inode);
|
||||
@ -788,6 +963,7 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
c->bi.nospace = c->bi.nospace_rp = 0;
|
||||
smp_wmb();
|
||||
}
|
||||
fscrypt_free_filename(&nm);
|
||||
return 0;
|
||||
|
||||
out_cancel:
|
||||
@ -798,6 +974,8 @@ out_cancel:
|
||||
unlock_2_inodes(dir, inode);
|
||||
if (budgeted)
|
||||
ubifs_release_budget(c, &req);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -806,8 +984,9 @@ 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);
|
||||
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
|
||||
@ -821,10 +1000,27 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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_budg;
|
||||
goto out_fname;
|
||||
}
|
||||
|
||||
err = ubifs_init_security(dir, inode, &dentry->d_name);
|
||||
@ -838,7 +1034,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
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);
|
||||
err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
|
||||
if (err) {
|
||||
ubifs_err(c, "cannot create directory, error %d", err);
|
||||
goto out_cancel;
|
||||
@ -847,6 +1043,7 @@ static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
|
||||
ubifs_release_budget(c, &req);
|
||||
d_instantiate(dentry, inode);
|
||||
fscrypt_free_filename(&nm);
|
||||
return 0;
|
||||
|
||||
out_cancel:
|
||||
@ -857,6 +1054,8 @@ out_cancel:
|
||||
out_inode:
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
out_budg:
|
||||
ubifs_release_budget(c, &req);
|
||||
return err;
|
||||
@ -870,11 +1069,12 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
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 sz_change;
|
||||
int err, devlen = 0;
|
||||
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
|
||||
.new_ino_d = ALIGN(devlen, 8),
|
||||
.dirtied_ino = 1 };
|
||||
struct fscrypt_name nm;
|
||||
|
||||
/*
|
||||
* Budget request settings: new inode, new direntry and changing parent
|
||||
@ -896,11 +1096,28 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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, mode);
|
||||
if (IS_ERR(inode)) {
|
||||
kfree(dev);
|
||||
err = PTR_ERR(inode);
|
||||
goto out_budg;
|
||||
goto out_fname;
|
||||
}
|
||||
|
||||
init_special_inode(inode, inode->i_mode, rdev);
|
||||
@ -917,7 +1134,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
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);
|
||||
err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
mutex_unlock(&dir_ui->ui_mutex);
|
||||
@ -925,6 +1142,7 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
ubifs_release_budget(c, &req);
|
||||
insert_inode_hash(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
fscrypt_free_filename(&nm);
|
||||
return 0;
|
||||
|
||||
out_cancel:
|
||||
@ -934,6 +1152,8 @@ out_cancel:
|
||||
out_inode:
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
out_budg:
|
||||
ubifs_release_budget(c, &req);
|
||||
return err;
|
||||
@ -947,10 +1167,27 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
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);
|
||||
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
|
||||
@ -960,36 +1197,77 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry,
|
||||
symname, dir->i_ino);
|
||||
|
||||
if (len > UBIFS_MAX_INO_DATA)
|
||||
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_budg;
|
||||
goto out_fname;
|
||||
}
|
||||
|
||||
ui = ubifs_inode(inode);
|
||||
ui->data = kmalloc(len + 1, GFP_NOFS);
|
||||
ui->data = kmalloc(disk_link.len, GFP_NOFS);
|
||||
if (!ui->data) {
|
||||
err = -ENOMEM;
|
||||
goto out_inode;
|
||||
}
|
||||
|
||||
memcpy(ui->data, symname, len);
|
||||
((char *)ui->data)[len] = '\0';
|
||||
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;
|
||||
}
|
||||
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err) {
|
||||
kfree(sd);
|
||||
goto out_inode;
|
||||
}
|
||||
|
||||
if (!fscrypt_has_encryption_key(inode)) {
|
||||
kfree(sd);
|
||||
err = -EPERM;
|
||||
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 = len;
|
||||
inode->i_size = ubifs_inode(inode)->ui_size = len;
|
||||
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)
|
||||
@ -999,7 +1277,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
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);
|
||||
err = ubifs_jnl_update(c, dir, &nm, inode, 0, 0);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
mutex_unlock(&dir_ui->ui_mutex);
|
||||
@ -1007,6 +1285,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
ubifs_release_budget(c, &req);
|
||||
insert_inode_hash(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
fscrypt_free_filename(&nm);
|
||||
return 0;
|
||||
|
||||
out_cancel:
|
||||
@ -1016,6 +1295,8 @@ out_cancel:
|
||||
out_inode:
|
||||
make_bad_inode(inode);
|
||||
iput(inode);
|
||||
out_fname:
|
||||
fscrypt_free_filename(&nm);
|
||||
out_budg:
|
||||
ubifs_release_budget(c, &req);
|
||||
return err;
|
||||
@ -1078,15 +1359,14 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
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;
|
||||
int new_sz = CALC_DENT_SIZE(new_dentry->d_name.len);
|
||||
int old_sz = CALC_DENT_SIZE(old_dentry->d_name.len);
|
||||
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;
|
||||
|
||||
if (flags & ~RENAME_NOREPLACE)
|
||||
return -EINVAL;
|
||||
@ -1107,17 +1387,41 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
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 = check_dir_empty(c, new_inode);
|
||||
err = ubifs_check_dir_empty(new_inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ubifs_budget_space(c, &req);
|
||||
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;
|
||||
}
|
||||
@ -1239,8 +1543,8 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
iput(whiteout);
|
||||
}
|
||||
|
||||
err = ubifs_jnl_rename(c, old_dir, old_dentry, new_dir, new_dentry, whiteout,
|
||||
sync);
|
||||
err = ubifs_jnl_rename(c, old_dir, old_inode, &old_nm, new_dir,
|
||||
new_inode, &new_nm, whiteout, sync);
|
||||
if (err)
|
||||
goto out_cancel;
|
||||
|
||||
@ -1256,6 +1560,9 @@ static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
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:
|
||||
@ -1284,6 +1591,8 @@ out_cancel:
|
||||
unlock_4_inodes(old_dir, new_dir, new_inode, whiteout);
|
||||
ubifs_release_budget(c, &ino_req);
|
||||
ubifs_release_budget(c, &req);
|
||||
fscrypt_free_filename(&old_nm);
|
||||
fscrypt_free_filename(&new_nm);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1298,9 +1607,27 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *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 = ubifs_current_time(old_dir);
|
||||
@ -1320,12 +1647,14 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
}
|
||||
}
|
||||
|
||||
err = ubifs_jnl_xrename(c, old_dir, old_dentry, new_dir, new_dentry,
|
||||
sync);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1384,6 +1713,14 @@ int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
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,
|
||||
@ -1410,6 +1747,7 @@ const struct file_operations ubifs_dir_operations = {
|
||||
.iterate_shared = ubifs_readdir,
|
||||
.fsync = ubifs_fsync,
|
||||
.unlocked_ioctl = ubifs_ioctl,
|
||||
.open = ubifs_dir_open,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ubifs_compat_ioctl,
|
||||
#endif
|
||||
|
108
fs/ubifs/file.c
108
fs/ubifs/file.c
@ -78,6 +78,13 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
|
||||
goto dump;
|
||||
|
||||
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
err = ubifs_decrypt(inode, dn, &dlen, block);
|
||||
if (err)
|
||||
goto dump;
|
||||
}
|
||||
|
||||
out_len = UBIFS_BLOCK_SIZE;
|
||||
err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
|
||||
le16_to_cpu(dn->compr_type));
|
||||
@ -650,6 +657,13 @@ static int populate_page(struct ubifs_info *c, struct page *page,
|
||||
|
||||
dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
out_len = UBIFS_BLOCK_SIZE;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
err = ubifs_decrypt(inode, dn, &dlen, page_block);
|
||||
if (err)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
err = ubifs_decompress(c, &dn->data, dlen, addr, &out_len,
|
||||
le16_to_cpu(dn->compr_type));
|
||||
if (err || len != out_len)
|
||||
@ -1594,6 +1608,15 @@ static const struct vm_operations_struct ubifs_file_vm_ops = {
|
||||
static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err)
|
||||
return -EACCES;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
|
||||
err = generic_file_mmap(file, vma);
|
||||
if (err)
|
||||
@ -1605,6 +1628,88 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ubifs_file_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int ret;
|
||||
struct dentry *dir;
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
ret = fscrypt_get_encryption_info(inode);
|
||||
if (ret)
|
||||
return -EACCES;
|
||||
if (!fscrypt_has_encryption_key(inode))
|
||||
return -ENOKEY;
|
||||
}
|
||||
|
||||
dir = dget_parent(file_dentry(filp));
|
||||
if (ubifs_crypt_is_encrypted(d_inode(dir)) &&
|
||||
!fscrypt_has_permitted_context(d_inode(dir), inode)) {
|
||||
ubifs_err(c, "Inconsistent encryption contexts: %lu/%lu",
|
||||
(unsigned long) d_inode(dir)->i_ino,
|
||||
(unsigned long) inode->i_ino);
|
||||
dput(dir);
|
||||
ubifs_ro_mode(c, -EPERM);
|
||||
return -EPERM;
|
||||
}
|
||||
dput(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *ubifs_get_link(struct dentry *dentry,
|
||||
struct inode *inode,
|
||||
struct delayed_call *done)
|
||||
{
|
||||
int err;
|
||||
struct fscrypt_symlink_data *sd;
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
struct fscrypt_str cstr;
|
||||
struct fscrypt_str pstr;
|
||||
|
||||
if (!ubifs_crypt_is_encrypted(inode))
|
||||
return ui->data;
|
||||
|
||||
if (!dentry)
|
||||
return ERR_PTR(-ECHILD);
|
||||
|
||||
err = fscrypt_get_encryption_info(inode);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
sd = (struct fscrypt_symlink_data *)ui->data;
|
||||
cstr.name = sd->encrypted_path;
|
||||
cstr.len = le16_to_cpu(sd->len);
|
||||
|
||||
if (cstr.len == 0)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > ui->data_len)
|
||||
return ERR_PTR(-EIO);
|
||||
|
||||
err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
|
||||
if (err) {
|
||||
fscrypt_fname_free_buffer(&pstr);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
pstr.name[pstr.len] = '\0';
|
||||
|
||||
// XXX this probably won't happen anymore...
|
||||
if (pstr.name[0] == '\0') {
|
||||
fscrypt_fname_free_buffer(&pstr);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
set_delayed_call(done, kfree_link, pstr.name);
|
||||
return pstr.name;
|
||||
}
|
||||
|
||||
|
||||
const struct address_space_operations ubifs_file_address_operations = {
|
||||
.readpage = ubifs_readpage,
|
||||
.writepage = ubifs_writepage,
|
||||
@ -1629,7 +1734,7 @@ const struct inode_operations ubifs_file_inode_operations = {
|
||||
|
||||
const struct inode_operations ubifs_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.get_link = simple_get_link,
|
||||
.get_link = ubifs_get_link,
|
||||
.setattr = ubifs_setattr,
|
||||
.getattr = ubifs_getattr,
|
||||
.listxattr = ubifs_listxattr,
|
||||
@ -1647,6 +1752,7 @@ const struct file_operations ubifs_file_operations = {
|
||||
.unlocked_ioctl = ubifs_ioctl,
|
||||
.splice_read = generic_file_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.open = ubifs_file_open,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = ubifs_compat_ioctl,
|
||||
#endif
|
||||
|
@ -846,10 +846,6 @@ int ubifs_gc_start_commit(struct ubifs_info *c)
|
||||
*/
|
||||
while (1) {
|
||||
lp = ubifs_fast_find_freeable(c);
|
||||
if (IS_ERR(lp)) {
|
||||
err = PTR_ERR(lp);
|
||||
goto out;
|
||||
}
|
||||
if (!lp)
|
||||
break;
|
||||
ubifs_assert(!(lp->flags & LPROPS_TAKEN));
|
||||
|
@ -452,16 +452,22 @@ static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
|
||||
*/
|
||||
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
|
||||
{
|
||||
ktime_t softlimit = ms_to_ktime(dirty_writeback_interval * 10);
|
||||
unsigned long long delta = dirty_writeback_interval;
|
||||
|
||||
/* centi to milli, milli to nano, then 10% */
|
||||
delta *= 10ULL * NSEC_PER_MSEC / 10ULL;
|
||||
|
||||
ubifs_assert(!hrtimer_active(&wbuf->timer));
|
||||
ubifs_assert(delta <= ULONG_MAX);
|
||||
|
||||
if (wbuf->no_timer)
|
||||
return;
|
||||
dbg_io("set timer for jhead %s, %llu-%llu millisecs",
|
||||
dbg_jhead(wbuf->jhead),
|
||||
div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
|
||||
div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
|
||||
USEC_PER_SEC));
|
||||
hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
|
||||
div_u64(ktime_to_ns(softlimit), USEC_PER_SEC),
|
||||
div_u64(ktime_to_ns(softlimit) + delta, USEC_PER_SEC));
|
||||
hrtimer_start_range_ns(&wbuf->timer, softlimit, delta,
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
@ -1059,10 +1065,6 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
|
||||
|
||||
hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
wbuf->timer.function = wbuf_timer_callback_nolock;
|
||||
wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||
wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||
wbuf->delta *= 1000000000ULL;
|
||||
ubifs_assert(wbuf->delta <= ULONG_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -181,6 +181,26 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
mnt_drop_write_file(file);
|
||||
return err;
|
||||
}
|
||||
case FS_IOC_SET_ENCRYPTION_POLICY: {
|
||||
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
|
||||
err = ubifs_enable_encryption(c);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return fscrypt_ioctl_set_policy(file, (const void __user *)arg);
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
case FS_IOC_GET_ENCRYPTION_POLICY: {
|
||||
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
return fscrypt_ioctl_get_policy(file, (void __user *)arg);
|
||||
#else
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
|
@ -78,16 +78,6 @@ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino)
|
||||
static inline void zero_dent_node_unused(struct ubifs_dent_node *dent)
|
||||
{
|
||||
dent->padding1 = 0;
|
||||
memset(dent->padding2, 0, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* zero_data_node_unused - zero out unused fields of an on-flash data node.
|
||||
* @data: the data node to zero out
|
||||
*/
|
||||
static inline void zero_data_node_unused(struct ubifs_data_node *data)
|
||||
{
|
||||
memset(data->padding, 0, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -511,6 +501,14 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
|
||||
ui->dirty = 0;
|
||||
}
|
||||
|
||||
static void set_dent_cookie(struct ubifs_info *c, struct ubifs_dent_node *dent)
|
||||
{
|
||||
if (c->double_hash)
|
||||
dent->cookie = prandom_u32();
|
||||
else
|
||||
dent->cookie = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_jnl_update - update inode.
|
||||
* @c: UBIFS file-system description object
|
||||
@ -539,7 +537,7 @@ static void mark_inode_clean(struct ubifs_info *c, struct ubifs_inode *ui)
|
||||
* success. In case of failure, a negative error code is returned.
|
||||
*/
|
||||
int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
|
||||
const struct qstr *nm, const struct inode *inode,
|
||||
const struct fscrypt_name *nm, const struct inode *inode,
|
||||
int deletion, int xent)
|
||||
{
|
||||
int err, dlen, ilen, len, lnum, ino_offs, dent_offs;
|
||||
@ -551,11 +549,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
|
||||
struct ubifs_ino_node *ino;
|
||||
union ubifs_key dent_key, ino_key;
|
||||
|
||||
dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
|
||||
inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
|
||||
//dbg_jnl("ino %lu, dent '%.*s', data len %d in dir ino %lu",
|
||||
// inode->i_ino, nm->len, nm->name, ui->data_len, dir->i_ino);
|
||||
ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
|
||||
|
||||
dlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
|
||||
dlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
|
||||
ilen = UBIFS_INO_NODE_SZ;
|
||||
|
||||
/*
|
||||
@ -596,9 +594,11 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
|
||||
key_write(c, &dent_key, dent->key);
|
||||
dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino);
|
||||
dent->type = get_dent_type(inode->i_mode);
|
||||
dent->nlen = cpu_to_le16(nm->len);
|
||||
memcpy(dent->name, nm->name, nm->len);
|
||||
dent->name[nm->len] = '\0';
|
||||
dent->nlen = cpu_to_le16(fname_len(nm));
|
||||
memcpy(dent->name, fname_name(nm), fname_len(nm));
|
||||
dent->name[fname_len(nm)] = '\0';
|
||||
set_dent_cookie(c, dent);
|
||||
|
||||
zero_dent_node_unused(dent);
|
||||
ubifs_prep_grp_node(c, dent, dlen, 0);
|
||||
|
||||
@ -697,14 +697,18 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
|
||||
const union ubifs_key *key, const void *buf, int len)
|
||||
{
|
||||
struct ubifs_data_node *data;
|
||||
int err, lnum, offs, compr_type, out_len;
|
||||
int err, lnum, offs, compr_type, out_len, compr_len;
|
||||
int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
bool encrypted = ubifs_crypt_is_encrypted(inode);
|
||||
|
||||
dbg_jnlk(key, "ino %lu, blk %u, len %d, key ",
|
||||
(unsigned long)key_inum(c, key), key_block(c, key), len);
|
||||
ubifs_assert(len <= UBIFS_BLOCK_SIZE);
|
||||
|
||||
if (encrypted)
|
||||
dlen += UBIFS_CIPHER_BLOCK_SIZE;
|
||||
|
||||
data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
|
||||
if (!data) {
|
||||
/*
|
||||
@ -722,7 +726,6 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
|
||||
data->ch.node_type = UBIFS_DATA_NODE;
|
||||
key_write(c, key, &data->key);
|
||||
data->size = cpu_to_le32(len);
|
||||
zero_data_node_unused(data);
|
||||
|
||||
if (!(ui->flags & UBIFS_COMPR_FL))
|
||||
/* Compression is disabled for this inode */
|
||||
@ -730,9 +733,18 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
|
||||
else
|
||||
compr_type = ui->compr_type;
|
||||
|
||||
out_len = dlen - UBIFS_DATA_NODE_SZ;
|
||||
ubifs_compress(c, buf, len, &data->data, &out_len, &compr_type);
|
||||
ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
|
||||
out_len = compr_len = dlen - UBIFS_DATA_NODE_SZ;
|
||||
ubifs_compress(c, buf, len, &data->data, &compr_len, &compr_type);
|
||||
ubifs_assert(compr_len <= UBIFS_BLOCK_SIZE);
|
||||
|
||||
if (encrypted) {
|
||||
err = ubifs_encrypt(inode, data, compr_len, &out_len, key_block(c, key));
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
} else {
|
||||
data->compr_size = 0;
|
||||
}
|
||||
|
||||
dlen = UBIFS_DATA_NODE_SZ + out_len;
|
||||
data->compr_type = cpu_to_le16(compr_type);
|
||||
@ -911,9 +923,11 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
* ubifs_jnl_xrename - cross rename two directory entries.
|
||||
* @c: UBIFS file-system description object
|
||||
* @fst_dir: parent inode of 1st directory entry to exchange
|
||||
* @fst_dentry: 1st directory entry to exchange
|
||||
* @fst_inode: 1st inode to exchange
|
||||
* @fst_nm: name of 1st inode to exchange
|
||||
* @snd_dir: parent inode of 2nd directory entry to exchange
|
||||
* @snd_dentry: 2nd directory entry to exchange
|
||||
* @snd_inode: 2nd inode to exchange
|
||||
* @snd_nm: name of 2nd inode to exchange
|
||||
* @sync: non-zero if the write-buffer has to be synchronized
|
||||
*
|
||||
* This function implements the cross rename operation which may involve
|
||||
@ -922,29 +936,29 @@ int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode)
|
||||
* returned.
|
||||
*/
|
||||
int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
|
||||
const struct dentry *fst_dentry,
|
||||
const struct inode *fst_inode,
|
||||
const struct fscrypt_name *fst_nm,
|
||||
const struct inode *snd_dir,
|
||||
const struct dentry *snd_dentry, int sync)
|
||||
const struct inode *snd_inode,
|
||||
const struct fscrypt_name *snd_nm, int sync)
|
||||
{
|
||||
union ubifs_key key;
|
||||
struct ubifs_dent_node *dent1, *dent2;
|
||||
int err, dlen1, dlen2, lnum, offs, len, plen = UBIFS_INO_NODE_SZ;
|
||||
int aligned_dlen1, aligned_dlen2;
|
||||
int twoparents = (fst_dir != snd_dir);
|
||||
const struct inode *fst_inode = d_inode(fst_dentry);
|
||||
const struct inode *snd_inode = d_inode(snd_dentry);
|
||||
void *p;
|
||||
|
||||
dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
|
||||
fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
|
||||
//dbg_jnl("dent '%pd' in dir ino %lu between dent '%pd' in dir ino %lu",
|
||||
// fst_dentry, fst_dir->i_ino, snd_dentry, snd_dir->i_ino);
|
||||
|
||||
ubifs_assert(ubifs_inode(fst_dir)->data_len == 0);
|
||||
ubifs_assert(ubifs_inode(snd_dir)->data_len == 0);
|
||||
ubifs_assert(mutex_is_locked(&ubifs_inode(fst_dir)->ui_mutex));
|
||||
ubifs_assert(mutex_is_locked(&ubifs_inode(snd_dir)->ui_mutex));
|
||||
|
||||
dlen1 = UBIFS_DENT_NODE_SZ + snd_dentry->d_name.len + 1;
|
||||
dlen2 = UBIFS_DENT_NODE_SZ + fst_dentry->d_name.len + 1;
|
||||
dlen1 = UBIFS_DENT_NODE_SZ + fname_len(snd_nm) + 1;
|
||||
dlen2 = UBIFS_DENT_NODE_SZ + fname_len(fst_nm) + 1;
|
||||
aligned_dlen1 = ALIGN(dlen1, 8);
|
||||
aligned_dlen2 = ALIGN(dlen2, 8);
|
||||
|
||||
@ -963,24 +977,24 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
|
||||
|
||||
/* Make new dent for 1st entry */
|
||||
dent1->ch.node_type = UBIFS_DENT_NODE;
|
||||
dent_key_init_flash(c, &dent1->key, snd_dir->i_ino, &snd_dentry->d_name);
|
||||
dent_key_init_flash(c, &dent1->key, snd_dir->i_ino, snd_nm);
|
||||
dent1->inum = cpu_to_le64(fst_inode->i_ino);
|
||||
dent1->type = get_dent_type(fst_inode->i_mode);
|
||||
dent1->nlen = cpu_to_le16(snd_dentry->d_name.len);
|
||||
memcpy(dent1->name, snd_dentry->d_name.name, snd_dentry->d_name.len);
|
||||
dent1->name[snd_dentry->d_name.len] = '\0';
|
||||
dent1->nlen = cpu_to_le16(fname_len(snd_nm));
|
||||
memcpy(dent1->name, fname_name(snd_nm), fname_len(snd_nm));
|
||||
dent1->name[fname_len(snd_nm)] = '\0';
|
||||
zero_dent_node_unused(dent1);
|
||||
ubifs_prep_grp_node(c, dent1, dlen1, 0);
|
||||
|
||||
/* Make new dent for 2nd entry */
|
||||
dent2 = (void *)dent1 + aligned_dlen1;
|
||||
dent2->ch.node_type = UBIFS_DENT_NODE;
|
||||
dent_key_init_flash(c, &dent2->key, fst_dir->i_ino, &fst_dentry->d_name);
|
||||
dent_key_init_flash(c, &dent2->key, fst_dir->i_ino, fst_nm);
|
||||
dent2->inum = cpu_to_le64(snd_inode->i_ino);
|
||||
dent2->type = get_dent_type(snd_inode->i_mode);
|
||||
dent2->nlen = cpu_to_le16(fst_dentry->d_name.len);
|
||||
memcpy(dent2->name, fst_dentry->d_name.name, fst_dentry->d_name.len);
|
||||
dent2->name[fst_dentry->d_name.len] = '\0';
|
||||
dent2->nlen = cpu_to_le16(fname_len(fst_nm));
|
||||
memcpy(dent2->name, fname_name(fst_nm), fname_len(fst_nm));
|
||||
dent2->name[fname_len(fst_nm)] = '\0';
|
||||
zero_dent_node_unused(dent2);
|
||||
ubifs_prep_grp_node(c, dent2, dlen2, 0);
|
||||
|
||||
@ -1004,14 +1018,14 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
|
||||
}
|
||||
release_head(c, BASEHD);
|
||||
|
||||
dent_key_init(c, &key, snd_dir->i_ino, &snd_dentry->d_name);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &snd_dentry->d_name);
|
||||
dent_key_init(c, &key, snd_dir->i_ino, snd_nm);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, snd_nm);
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
offs += aligned_dlen1;
|
||||
dent_key_init(c, &key, fst_dir->i_ino, &fst_dentry->d_name);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &fst_dentry->d_name);
|
||||
dent_key_init(c, &key, fst_dir->i_ino, fst_nm);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, fst_nm);
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
@ -1063,31 +1077,31 @@ out_free:
|
||||
* returned.
|
||||
*/
|
||||
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
const struct dentry *old_dentry,
|
||||
const struct inode *old_inode,
|
||||
const struct fscrypt_name *old_nm,
|
||||
const struct inode *new_dir,
|
||||
const struct dentry *new_dentry,
|
||||
const struct inode *new_inode,
|
||||
const struct fscrypt_name *new_nm,
|
||||
const struct inode *whiteout, int sync)
|
||||
{
|
||||
void *p;
|
||||
union ubifs_key key;
|
||||
struct ubifs_dent_node *dent, *dent2;
|
||||
int err, dlen1, dlen2, ilen, lnum, offs, len;
|
||||
const struct inode *old_inode = d_inode(old_dentry);
|
||||
const struct inode *new_inode = d_inode(new_dentry);
|
||||
int aligned_dlen1, aligned_dlen2, plen = UBIFS_INO_NODE_SZ;
|
||||
int last_reference = !!(new_inode && new_inode->i_nlink == 0);
|
||||
int move = (old_dir != new_dir);
|
||||
struct ubifs_inode *uninitialized_var(new_ui);
|
||||
|
||||
dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
|
||||
old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
|
||||
//dbg_jnl("dent '%pd' in dir ino %lu to dent '%pd' in dir ino %lu",
|
||||
// old_dentry, old_dir->i_ino, new_dentry, new_dir->i_ino);
|
||||
ubifs_assert(ubifs_inode(old_dir)->data_len == 0);
|
||||
ubifs_assert(ubifs_inode(new_dir)->data_len == 0);
|
||||
ubifs_assert(mutex_is_locked(&ubifs_inode(old_dir)->ui_mutex));
|
||||
ubifs_assert(mutex_is_locked(&ubifs_inode(new_dir)->ui_mutex));
|
||||
|
||||
dlen1 = UBIFS_DENT_NODE_SZ + new_dentry->d_name.len + 1;
|
||||
dlen2 = UBIFS_DENT_NODE_SZ + old_dentry->d_name.len + 1;
|
||||
dlen1 = UBIFS_DENT_NODE_SZ + fname_len(new_nm) + 1;
|
||||
dlen2 = UBIFS_DENT_NODE_SZ + fname_len(old_nm) + 1;
|
||||
if (new_inode) {
|
||||
new_ui = ubifs_inode(new_inode);
|
||||
ubifs_assert(mutex_is_locked(&new_ui->ui_mutex));
|
||||
@ -1113,19 +1127,19 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
|
||||
/* Make new dent */
|
||||
dent->ch.node_type = UBIFS_DENT_NODE;
|
||||
dent_key_init_flash(c, &dent->key, new_dir->i_ino, &new_dentry->d_name);
|
||||
dent_key_init_flash(c, &dent->key, new_dir->i_ino, new_nm);
|
||||
dent->inum = cpu_to_le64(old_inode->i_ino);
|
||||
dent->type = get_dent_type(old_inode->i_mode);
|
||||
dent->nlen = cpu_to_le16(new_dentry->d_name.len);
|
||||
memcpy(dent->name, new_dentry->d_name.name, new_dentry->d_name.len);
|
||||
dent->name[new_dentry->d_name.len] = '\0';
|
||||
dent->nlen = cpu_to_le16(fname_len(new_nm));
|
||||
memcpy(dent->name, fname_name(new_nm), fname_len(new_nm));
|
||||
dent->name[fname_len(new_nm)] = '\0';
|
||||
set_dent_cookie(c, dent);
|
||||
zero_dent_node_unused(dent);
|
||||
ubifs_prep_grp_node(c, dent, dlen1, 0);
|
||||
|
||||
dent2 = (void *)dent + aligned_dlen1;
|
||||
dent2->ch.node_type = UBIFS_DENT_NODE;
|
||||
dent_key_init_flash(c, &dent2->key, old_dir->i_ino,
|
||||
&old_dentry->d_name);
|
||||
dent_key_init_flash(c, &dent2->key, old_dir->i_ino, old_nm);
|
||||
|
||||
if (whiteout) {
|
||||
dent2->inum = cpu_to_le64(whiteout->i_ino);
|
||||
@ -1135,9 +1149,10 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
dent2->inum = 0;
|
||||
dent2->type = DT_UNKNOWN;
|
||||
}
|
||||
dent2->nlen = cpu_to_le16(old_dentry->d_name.len);
|
||||
memcpy(dent2->name, old_dentry->d_name.name, old_dentry->d_name.len);
|
||||
dent2->name[old_dentry->d_name.len] = '\0';
|
||||
dent2->nlen = cpu_to_le16(fname_len(old_nm));
|
||||
memcpy(dent2->name, fname_name(old_nm), fname_len(old_nm));
|
||||
dent2->name[fname_len(old_nm)] = '\0';
|
||||
set_dent_cookie(c, dent2);
|
||||
zero_dent_node_unused(dent2);
|
||||
ubifs_prep_grp_node(c, dent2, dlen2, 0);
|
||||
|
||||
@ -1178,15 +1193,15 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
}
|
||||
release_head(c, BASEHD);
|
||||
|
||||
dent_key_init(c, &key, new_dir->i_ino, &new_dentry->d_name);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, &new_dentry->d_name);
|
||||
dent_key_init(c, &key, new_dir->i_ino, new_nm);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, new_nm);
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
offs += aligned_dlen1;
|
||||
if (whiteout) {
|
||||
dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, &old_dentry->d_name);
|
||||
dent_key_init(c, &key, old_dir->i_ino, old_nm);
|
||||
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, old_nm);
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
@ -1196,8 +1211,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
if (err)
|
||||
goto out_ro;
|
||||
|
||||
dent_key_init(c, &key, old_dir->i_ino, &old_dentry->d_name);
|
||||
err = ubifs_tnc_remove_nm(c, &key, &old_dentry->d_name);
|
||||
dent_key_init(c, &key, old_dir->i_ino, old_nm);
|
||||
err = ubifs_tnc_remove_nm(c, &key, old_nm);
|
||||
if (err)
|
||||
goto out_ro;
|
||||
}
|
||||
@ -1251,31 +1266,55 @@ out_free:
|
||||
}
|
||||
|
||||
/**
|
||||
* recomp_data_node - re-compress a truncated data node.
|
||||
* truncate_data_node - re-compress/encrypt a truncated data node.
|
||||
* @c: UBIFS file-system description object
|
||||
* @inode: inode which referes to the data node
|
||||
* @block: data block number
|
||||
* @dn: data node to re-compress
|
||||
* @new_len: new length
|
||||
*
|
||||
* This function is used when an inode is truncated and the last data node of
|
||||
* the inode has to be re-compressed and re-written.
|
||||
* the inode has to be re-compressed/encrypted and re-written.
|
||||
*/
|
||||
static int recomp_data_node(const struct ubifs_info *c,
|
||||
struct ubifs_data_node *dn, int *new_len)
|
||||
static int truncate_data_node(const struct ubifs_info *c, const struct inode *inode,
|
||||
unsigned int block, struct ubifs_data_node *dn,
|
||||
int *new_len)
|
||||
{
|
||||
void *buf;
|
||||
int err, len, compr_type, out_len;
|
||||
int err, dlen, compr_type, out_len, old_dlen;
|
||||
|
||||
out_len = le32_to_cpu(dn->size);
|
||||
buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
len = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
dlen = old_dlen = le32_to_cpu(dn->ch.len) - UBIFS_DATA_NODE_SZ;
|
||||
compr_type = le16_to_cpu(dn->compr_type);
|
||||
err = ubifs_decompress(c, &dn->data, len, buf, &out_len, compr_type);
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
err = ubifs_decrypt(inode, dn, &dlen, block);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (compr_type != UBIFS_COMPR_NONE) {
|
||||
err = ubifs_decompress(c, &dn->data, dlen, buf, &out_len, compr_type);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
ubifs_compress(c, buf, *new_len, &dn->data, &out_len, &compr_type);
|
||||
}
|
||||
|
||||
if (ubifs_crypt_is_encrypted(inode)) {
|
||||
err = ubifs_encrypt(inode, dn, out_len, &old_dlen, block);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
out_len = old_dlen;
|
||||
} else {
|
||||
dn->compr_size = 0;
|
||||
}
|
||||
|
||||
ubifs_assert(out_len <= UBIFS_BLOCK_SIZE);
|
||||
dn->compr_type = cpu_to_le16(compr_type);
|
||||
dn->size = cpu_to_le32(*new_len);
|
||||
@ -1347,17 +1386,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
|
||||
if (le32_to_cpu(dn->size) <= dlen)
|
||||
dlen = 0; /* Nothing to do */
|
||||
else {
|
||||
int compr_type = le16_to_cpu(dn->compr_type);
|
||||
|
||||
if (compr_type != UBIFS_COMPR_NONE) {
|
||||
err = recomp_data_node(c, dn, &dlen);
|
||||
err = truncate_data_node(c, inode, blk, dn, &dlen);
|
||||
if (err)
|
||||
goto out_free;
|
||||
} else {
|
||||
dn->size = cpu_to_le32(dlen);
|
||||
dlen += UBIFS_DATA_NODE_SZ;
|
||||
}
|
||||
zero_data_node_unused(dn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1442,7 +1473,8 @@ out_free:
|
||||
* error code in case of failure.
|
||||
*/
|
||||
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
|
||||
const struct inode *inode, const struct qstr *nm)
|
||||
const struct inode *inode,
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen;
|
||||
struct ubifs_dent_node *xent;
|
||||
@ -1451,9 +1483,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
|
||||
int sync = IS_DIRSYNC(host);
|
||||
struct ubifs_inode *host_ui = ubifs_inode(host);
|
||||
|
||||
dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
|
||||
host->i_ino, inode->i_ino, nm->name,
|
||||
ubifs_inode(inode)->data_len);
|
||||
//dbg_jnl("host %lu, xattr ino %lu, name '%s', data len %d",
|
||||
// host->i_ino, inode->i_ino, nm->name,
|
||||
// ubifs_inode(inode)->data_len);
|
||||
ubifs_assert(inode->i_nlink == 0);
|
||||
ubifs_assert(mutex_is_locked(&host_ui->ui_mutex));
|
||||
|
||||
@ -1461,7 +1493,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
|
||||
* Since we are deleting the inode, we do not bother to attach any data
|
||||
* to it and assume its length is %UBIFS_INO_NODE_SZ.
|
||||
*/
|
||||
xlen = UBIFS_DENT_NODE_SZ + nm->len + 1;
|
||||
xlen = UBIFS_DENT_NODE_SZ + fname_len(nm) + 1;
|
||||
aligned_xlen = ALIGN(xlen, 8);
|
||||
hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
|
||||
len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
|
||||
@ -1482,9 +1514,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
|
||||
key_write(c, &xent_key, xent->key);
|
||||
xent->inum = 0;
|
||||
xent->type = get_dent_type(inode->i_mode);
|
||||
xent->nlen = cpu_to_le16(nm->len);
|
||||
memcpy(xent->name, nm->name, nm->len);
|
||||
xent->name[nm->len] = '\0';
|
||||
xent->nlen = cpu_to_le16(fname_len(nm));
|
||||
memcpy(xent->name, fname_name(nm), fname_len(nm));
|
||||
xent->name[fname_len(nm)] = '\0';
|
||||
zero_dent_node_unused(xent);
|
||||
ubifs_prep_grp_node(c, xent, xlen, 0);
|
||||
|
||||
|
@ -69,7 +69,7 @@ static inline uint32_t key_r5_hash(const char *s, int len)
|
||||
uint32_t a = 0;
|
||||
const signed char *str = (const signed char *)s;
|
||||
|
||||
while (*str) {
|
||||
while (len--) {
|
||||
a += *str << 4;
|
||||
a += *str >> 4;
|
||||
a *= 11;
|
||||
@ -153,13 +153,13 @@ static inline void highest_ino_key(const struct ubifs_info *c,
|
||||
* @c: UBIFS file-system description object
|
||||
* @key: key to initialize
|
||||
* @inum: parent inode number
|
||||
* @nm: direntry name and length
|
||||
* @nm: direntry name and length. Not a string when encrypted!
|
||||
*/
|
||||
static inline void dent_key_init(const struct ubifs_info *c,
|
||||
union ubifs_key *key, ino_t inum,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
uint32_t hash = c->key_hash(nm->name, nm->len);
|
||||
uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
|
||||
|
||||
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
|
||||
key->u32[0] = inum;
|
||||
@ -191,10 +191,11 @@ static inline void dent_key_init_hash(const struct ubifs_info *c,
|
||||
* @nm: direntry name and length
|
||||
*/
|
||||
static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
|
||||
ino_t inum, const struct qstr *nm)
|
||||
ino_t inum,
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
union ubifs_key *key = k;
|
||||
uint32_t hash = c->key_hash(nm->name, nm->len);
|
||||
uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
|
||||
|
||||
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
|
||||
key->j32[0] = cpu_to_le32(inum);
|
||||
@ -225,9 +226,9 @@ static inline void lowest_dent_key(const struct ubifs_info *c,
|
||||
*/
|
||||
static inline void xent_key_init(const struct ubifs_info *c,
|
||||
union ubifs_key *key, ino_t inum,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
uint32_t hash = c->key_hash(nm->name, nm->len);
|
||||
uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
|
||||
|
||||
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
|
||||
key->u32[0] = inum;
|
||||
@ -242,10 +243,10 @@ static inline void xent_key_init(const struct ubifs_info *c,
|
||||
* @nm: extended attribute entry name and length
|
||||
*/
|
||||
static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
|
||||
ino_t inum, const struct qstr *nm)
|
||||
ino_t inum, const struct fscrypt_name *nm)
|
||||
{
|
||||
union ubifs_key *key = k;
|
||||
uint32_t hash = c->key_hash(nm->name, nm->len);
|
||||
uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
|
||||
|
||||
ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
|
||||
key->j32[0] = cpu_to_le32(inum);
|
||||
|
@ -61,7 +61,7 @@ struct replay_entry {
|
||||
struct list_head list;
|
||||
union ubifs_key key;
|
||||
union {
|
||||
struct qstr nm;
|
||||
struct fscrypt_name nm;
|
||||
struct {
|
||||
loff_t old_size;
|
||||
loff_t new_size;
|
||||
@ -327,7 +327,7 @@ static void destroy_replay_list(struct ubifs_info *c)
|
||||
|
||||
list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
|
||||
if (is_hash_key(c, &r->key))
|
||||
kfree(r->nm.name);
|
||||
kfree(fname_name(&r->nm));
|
||||
list_del(&r->list);
|
||||
kfree(r);
|
||||
}
|
||||
@ -430,10 +430,10 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
|
||||
r->deletion = !!deletion;
|
||||
r->sqnum = sqnum;
|
||||
key_copy(c, key, &r->key);
|
||||
r->nm.len = nlen;
|
||||
fname_len(&r->nm) = nlen;
|
||||
memcpy(nbuf, name, nlen);
|
||||
nbuf[nlen] = '\0';
|
||||
r->nm.name = nbuf;
|
||||
fname_name(&r->nm) = nbuf;
|
||||
|
||||
list_add_tail(&r->list, &c->replay_list);
|
||||
return 0;
|
||||
@ -456,7 +456,7 @@ int ubifs_validate_entry(struct ubifs_info *c,
|
||||
if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
|
||||
dent->type >= UBIFS_ITYPES_CNT ||
|
||||
nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
|
||||
strnlen(dent->name, nlen) != nlen ||
|
||||
(key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) ||
|
||||
le64_to_cpu(dent->inum) > MAX_INUM) {
|
||||
ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ?
|
||||
"directory entry" : "extended attribute entry");
|
||||
|
@ -163,6 +163,7 @@ static int create_default_filesystem(struct ubifs_info *c)
|
||||
tmp64 = (long long)max_buds * c->leb_size;
|
||||
if (big_lpt)
|
||||
sup_flags |= UBIFS_FLG_BIGLPT;
|
||||
sup_flags |= UBIFS_FLG_DOUBLE_HASH;
|
||||
|
||||
sup->ch.node_type = UBIFS_SB_NODE;
|
||||
sup->key_hash = UBIFS_KEY_HASH_R5;
|
||||
@ -465,6 +466,16 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (!c->double_hash && c->fmt_version >= 5) {
|
||||
err = 16;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (c->encrypted && c->fmt_version < 5) {
|
||||
err = 17;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
@ -620,6 +631,24 @@ int ubifs_read_superblock(struct ubifs_info *c)
|
||||
memcpy(&c->uuid, &sup->uuid, 16);
|
||||
c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
|
||||
c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
|
||||
c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
|
||||
c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
|
||||
|
||||
if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
|
||||
ubifs_err(c, "Unknown feature flags found: %#x",
|
||||
sup_flags & ~UBIFS_FLG_MASK);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
if (c->encrypted) {
|
||||
ubifs_err(c, "file system contains encrypted files but UBIFS"
|
||||
" was built without crypto support.");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Automatically increase file system size to the maximum size */
|
||||
c->old_leb_cnt = c->leb_cnt;
|
||||
@ -807,3 +836,33 @@ int ubifs_fixup_free_space(struct ubifs_info *c)
|
||||
ubifs_msg(c, "free space fixup complete");
|
||||
return err;
|
||||
}
|
||||
|
||||
int ubifs_enable_encryption(struct ubifs_info *c)
|
||||
{
|
||||
int err;
|
||||
struct ubifs_sb_node *sup;
|
||||
|
||||
if (c->encrypted)
|
||||
return 0;
|
||||
|
||||
if (c->ro_mount || c->ro_media)
|
||||
return -EROFS;
|
||||
|
||||
if (c->fmt_version < 5) {
|
||||
ubifs_err(c, "on-flash format version 5 is needed for encryption");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sup = ubifs_read_sb_node(c);
|
||||
if (IS_ERR(sup))
|
||||
return PTR_ERR(sup);
|
||||
|
||||
sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION);
|
||||
|
||||
err = ubifs_write_sb_node(c, sup);
|
||||
if (!err)
|
||||
c->encrypted = 1;
|
||||
kfree(sup);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -198,7 +198,6 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
|
||||
}
|
||||
memcpy(ui->data, ino->data, ui->data_len);
|
||||
((char *)ui->data)[ui->data_len] = '\0';
|
||||
inode->i_link = ui->data;
|
||||
break;
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
@ -380,6 +379,9 @@ out:
|
||||
}
|
||||
done:
|
||||
clear_inode(inode);
|
||||
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
fscrypt_put_encryption_info(inode, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ubifs_dirty_inode(struct inode *inode, int flags)
|
||||
@ -1207,7 +1209,8 @@ static int mount_ubifs(struct ubifs_info *c)
|
||||
bu_init(c);
|
||||
|
||||
if (!c->ro_mount) {
|
||||
c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
|
||||
c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
|
||||
UBIFS_CIPHER_BLOCK_SIZE,
|
||||
GFP_KERNEL);
|
||||
if (!c->write_reserve_buf)
|
||||
goto out_free;
|
||||
@ -1620,7 +1623,8 @@ static int ubifs_remount_rw(struct ubifs_info *c)
|
||||
goto out;
|
||||
}
|
||||
|
||||
c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
|
||||
c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ + \
|
||||
UBIFS_CIPHER_BLOCK_SIZE, GFP_KERNEL);
|
||||
if (!c->write_reserve_buf) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
@ -1995,6 +1999,12 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
struct fscrypt_operations ubifs_crypt_operations = {
|
||||
.is_encrypted = __ubifs_crypt_is_encrypted,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
{
|
||||
struct ubifs_info *c = sb->s_fs_info;
|
||||
@ -2041,6 +2051,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
|
||||
sb->s_op = &ubifs_super_operations;
|
||||
sb->s_xattr = ubifs_xattr_handlers;
|
||||
sb->s_cop = &ubifs_crypt_operations;
|
||||
|
||||
mutex_lock(&c->umount_mutex);
|
||||
err = mount_ubifs(c);
|
||||
|
157
fs/ubifs/tnc.c
157
fs/ubifs/tnc.c
@ -378,7 +378,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
|
||||
}
|
||||
|
||||
/**
|
||||
* tnc_read_node_nm - read a "hashed" leaf node.
|
||||
* tnc_read_hashed_node - read a "hashed" leaf node.
|
||||
* @c: UBIFS file-system description object
|
||||
* @zbr: key and position of the node
|
||||
* @node: node is returned here
|
||||
@ -388,7 +388,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
|
||||
* added to LNC. Returns zero in case of success or a negative negative error
|
||||
* code in case of failure.
|
||||
*/
|
||||
static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
||||
static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
||||
void *node)
|
||||
{
|
||||
int err;
|
||||
@ -519,7 +519,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
|
||||
* of failure, a negative error code is returned.
|
||||
*/
|
||||
static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
struct ubifs_dent_node *dent;
|
||||
int nlen, err;
|
||||
@ -542,11 +542,11 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
|
||||
dent = zbr->leaf;
|
||||
|
||||
nlen = le16_to_cpu(dent->nlen);
|
||||
err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
|
||||
err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
|
||||
if (err == 0) {
|
||||
if (nlen == nm->len)
|
||||
if (nlen == fname_len(nm))
|
||||
return NAME_MATCHES;
|
||||
else if (nlen < nm->len)
|
||||
else if (nlen < fname_len(nm))
|
||||
return NAME_LESS;
|
||||
else
|
||||
return NAME_GREATER;
|
||||
@ -689,7 +689,7 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
|
||||
*/
|
||||
static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
|
||||
struct ubifs_znode **zn, int *n,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
int err;
|
||||
|
||||
@ -807,7 +807,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
|
||||
*/
|
||||
static int fallible_matches_name(struct ubifs_info *c,
|
||||
struct ubifs_zbranch *zbr,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
struct ubifs_dent_node *dent;
|
||||
int nlen, err;
|
||||
@ -835,11 +835,11 @@ static int fallible_matches_name(struct ubifs_info *c,
|
||||
dent = zbr->leaf;
|
||||
|
||||
nlen = le16_to_cpu(dent->nlen);
|
||||
err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
|
||||
err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
|
||||
if (err == 0) {
|
||||
if (nlen == nm->len)
|
||||
if (nlen == fname_len(nm))
|
||||
return NAME_MATCHES;
|
||||
else if (nlen < nm->len)
|
||||
else if (nlen < fname_len(nm))
|
||||
return NAME_LESS;
|
||||
else
|
||||
return NAME_GREATER;
|
||||
@ -878,7 +878,8 @@ out_free:
|
||||
static int fallible_resolve_collision(struct ubifs_info *c,
|
||||
const union ubifs_key *key,
|
||||
struct ubifs_znode **zn, int *n,
|
||||
const struct qstr *nm, int adding)
|
||||
const struct fscrypt_name *nm,
|
||||
int adding)
|
||||
{
|
||||
struct ubifs_znode *o_znode = NULL, *znode = *zn;
|
||||
int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
|
||||
@ -1453,7 +1454,7 @@ again:
|
||||
* In this case the leaf node cache gets used, so we pass the
|
||||
* address of the zbranch and keep the mutex locked
|
||||
*/
|
||||
err = tnc_read_node_nm(c, zt, node);
|
||||
err = tnc_read_hashed_node(c, zt, node);
|
||||
goto out;
|
||||
}
|
||||
if (safely) {
|
||||
@ -1782,19 +1783,19 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
|
||||
* @node: the node is returned here
|
||||
* @nm: node name
|
||||
*
|
||||
* This function look up and reads a node which contains name hash in the key.
|
||||
* This function looks up and reads a node which contains name hash in the key.
|
||||
* Since the hash may have collisions, there may be many nodes with the same
|
||||
* key, so we have to sequentially look to all of them until the needed one is
|
||||
* found. This function returns zero in case of success, %-ENOENT if the node
|
||||
* was not found, and a negative error code in case of failure.
|
||||
*/
|
||||
static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
void *node, const struct qstr *nm)
|
||||
void *node, const struct fscrypt_name *nm)
|
||||
{
|
||||
int found, n, err;
|
||||
struct ubifs_znode *znode;
|
||||
|
||||
dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
|
||||
//dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
found = ubifs_lookup_level0(c, key, &znode, &n);
|
||||
if (!found) {
|
||||
@ -1816,7 +1817,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = tnc_read_node_nm(c, &znode->zbranch[n], node);
|
||||
err = tnc_read_hashed_node(c, &znode->zbranch[n], node);
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&c->tnc_mutex);
|
||||
@ -1830,14 +1831,14 @@ out_unlock:
|
||||
* @node: the node is returned here
|
||||
* @nm: node name
|
||||
*
|
||||
* This function look up and reads a node which contains name hash in the key.
|
||||
* This function looks up and reads a node which contains name hash in the key.
|
||||
* Since the hash may have collisions, there may be many nodes with the same
|
||||
* key, so we have to sequentially look to all of them until the needed one is
|
||||
* found. This function returns zero in case of success, %-ENOENT if the node
|
||||
* was not found, and a negative error code in case of failure.
|
||||
*/
|
||||
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
void *node, const struct qstr *nm)
|
||||
void *node, const struct fscrypt_name *nm)
|
||||
{
|
||||
int err, len;
|
||||
const struct ubifs_dent_node *dent = node;
|
||||
@ -1851,16 +1852,105 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
return err;
|
||||
|
||||
len = le16_to_cpu(dent->nlen);
|
||||
if (nm->len == len && !memcmp(dent->name, nm->name, len))
|
||||
if (fname_len(nm) == len && !memcmp(dent->name, fname_name(nm), len))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Unluckily, there are hash collisions and we have to iterate over
|
||||
* them look at each direntry with colliding name hash sequentially.
|
||||
*/
|
||||
|
||||
return do_lookup_nm(c, key, node, nm);
|
||||
}
|
||||
|
||||
static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
|
||||
struct ubifs_dent_node *dent, uint32_t cookie)
|
||||
{
|
||||
int n, err, type = key_type(c, key);
|
||||
struct ubifs_znode *znode;
|
||||
struct ubifs_zbranch *zbr;
|
||||
union ubifs_key *dkey, start_key;
|
||||
|
||||
ubifs_assert(is_hash_key(c, key));
|
||||
|
||||
lowest_dent_key(c, &start_key, key_inum(c, key));
|
||||
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
err = ubifs_lookup_level0(c, &start_key, &znode, &n);
|
||||
if (unlikely(err < 0))
|
||||
goto out_unlock;
|
||||
|
||||
for (;;) {
|
||||
if (!err) {
|
||||
err = tnc_next(c, &znode, &n);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
zbr = &znode->zbranch[n];
|
||||
dkey = &zbr->key;
|
||||
|
||||
if (key_inum(c, dkey) != key_inum(c, key) ||
|
||||
key_type(c, dkey) != type) {
|
||||
err = -ENOENT;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
err = tnc_read_hashed_node(c, zbr, dent);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
|
||||
if (key_hash(c, key) == key_hash(c, dkey) &&
|
||||
le32_to_cpu(dent->cookie) == cookie)
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&c->tnc_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* ubifs_tnc_lookup_dh - look up a "double hashed" node.
|
||||
* @c: UBIFS file-system description object
|
||||
* @key: node key to lookup
|
||||
* @node: the node is returned here
|
||||
* @cookie: node cookie for collision resolution
|
||||
*
|
||||
* This function looks up and reads a node which contains name hash in the key.
|
||||
* Since the hash may have collisions, there may be many nodes with the same
|
||||
* key, so we have to sequentially look to all of them until the needed one
|
||||
* with the same cookie value is found.
|
||||
* This function returns zero in case of success, %-ENOENT if the node
|
||||
* was not found, and a negative error code in case of failure.
|
||||
*/
|
||||
int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
|
||||
void *node, uint32_t cookie)
|
||||
{
|
||||
int err;
|
||||
const struct ubifs_dent_node *dent = node;
|
||||
|
||||
if (!c->double_hash)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* We assume that in most of the cases there are no name collisions and
|
||||
* 'ubifs_tnc_lookup()' returns us the right direntry.
|
||||
*/
|
||||
err = ubifs_tnc_lookup(c, key, node);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (le32_to_cpu(dent->cookie) == cookie)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Unluckily, there are hash collisions and we have to iterate over
|
||||
* them look at each direntry with colliding name hash sequentially.
|
||||
*/
|
||||
return do_lookup_dh(c, key, node, cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* correct_parent_keys - correct parent znodes' keys.
|
||||
* @c: UBIFS file-system description object
|
||||
@ -2279,14 +2369,15 @@ out_unlock:
|
||||
* may have collisions, like directory entry keys.
|
||||
*/
|
||||
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
int lnum, int offs, int len, const struct qstr *nm)
|
||||
int lnum, int offs, int len,
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
int found, n, err = 0;
|
||||
struct ubifs_znode *znode;
|
||||
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
|
||||
lnum, offs, nm->len, nm->name);
|
||||
//dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
|
||||
// lnum, offs, nm->len, nm->name);
|
||||
found = lookup_level0_dirty(c, key, &znode, &n);
|
||||
if (found < 0) {
|
||||
err = found;
|
||||
@ -2344,7 +2435,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
* by passing 'ubifs_tnc_remove_nm()' the same key but
|
||||
* an unmatchable name.
|
||||
*/
|
||||
struct qstr noname = { .name = "" };
|
||||
struct fscrypt_name noname = { .disk_name = { .name = "", .len = 1 } };
|
||||
|
||||
err = dbg_check_tnc(c, 0);
|
||||
mutex_unlock(&c->tnc_mutex);
|
||||
@ -2514,13 +2605,13 @@ out_unlock:
|
||||
* Returns %0 on success or negative error code on failure.
|
||||
*/
|
||||
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
int n, err;
|
||||
struct ubifs_znode *znode;
|
||||
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
|
||||
//dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
|
||||
err = lookup_level0_dirty(c, key, &znode, &n);
|
||||
if (err < 0)
|
||||
goto out_unlock;
|
||||
@ -2669,7 +2760,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
|
||||
{
|
||||
union ubifs_key key1, key2;
|
||||
struct ubifs_dent_node *xent, *pxent = NULL;
|
||||
struct qstr nm = { .name = NULL };
|
||||
struct fscrypt_name nm = {0};
|
||||
|
||||
dbg_tnc("ino %lu", (unsigned long)inum);
|
||||
|
||||
@ -2694,8 +2785,8 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
|
||||
dbg_tnc("xent '%s', ino %lu", xent->name,
|
||||
(unsigned long)xattr_inum);
|
||||
|
||||
nm.name = xent->name;
|
||||
nm.len = le16_to_cpu(xent->nlen);
|
||||
fname_name(&nm) = xent->name;
|
||||
fname_len(&nm) = le16_to_cpu(xent->nlen);
|
||||
err = ubifs_tnc_remove_nm(c, &key1, &nm);
|
||||
if (err) {
|
||||
kfree(xent);
|
||||
@ -2747,7 +2838,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
|
||||
*/
|
||||
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
|
||||
union ubifs_key *key,
|
||||
const struct qstr *nm)
|
||||
const struct fscrypt_name *nm)
|
||||
{
|
||||
int n, err, type = key_type(c, key);
|
||||
struct ubifs_znode *znode;
|
||||
@ -2755,7 +2846,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
|
||||
struct ubifs_zbranch *zbr;
|
||||
union ubifs_key *dkey;
|
||||
|
||||
dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
|
||||
//dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
|
||||
ubifs_assert(is_hash_key(c, key));
|
||||
|
||||
mutex_lock(&c->tnc_mutex);
|
||||
@ -2763,7 +2854,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
|
||||
if (unlikely(err < 0))
|
||||
goto out_unlock;
|
||||
|
||||
if (nm->name) {
|
||||
if (fname_len(nm) > 0) {
|
||||
if (err) {
|
||||
/* Handle collisions */
|
||||
err = resolve_collision(c, key, &znode, &n, nm);
|
||||
@ -2813,7 +2904,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
err = tnc_read_node_nm(c, zbr, dent);
|
||||
err = tnc_read_hashed_node(c, zbr, dent);
|
||||
if (unlikely(err))
|
||||
goto out_free;
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
* UBIFS went into mainline kernel with format version 4. The older formats
|
||||
* were development formats.
|
||||
*/
|
||||
#define UBIFS_FORMAT_VERSION 4
|
||||
#define UBIFS_FORMAT_VERSION 5
|
||||
|
||||
/*
|
||||
* Read-only compatibility version. If the UBIFS format is changed, older UBIFS
|
||||
@ -300,6 +300,13 @@ enum {
|
||||
/* The largest UBIFS node */
|
||||
#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
|
||||
|
||||
/*
|
||||
* xattr name of UBIFS encryption context, we don't use a prefix
|
||||
* nor a long name to not waste space on the flash.
|
||||
*/
|
||||
#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
|
||||
|
||||
|
||||
/*
|
||||
* On-flash inode flags.
|
||||
*
|
||||
@ -309,6 +316,7 @@ enum {
|
||||
* UBIFS_APPEND_FL: writes to the inode may only append data
|
||||
* UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
|
||||
* UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
|
||||
* UBIFS_CRYPT_FL: use encryption for this inode
|
||||
*
|
||||
* Note, these are on-flash flags which correspond to ioctl flags
|
||||
* (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
|
||||
@ -321,6 +329,7 @@ enum {
|
||||
UBIFS_APPEND_FL = 0x08,
|
||||
UBIFS_DIRSYNC_FL = 0x10,
|
||||
UBIFS_XATTR_FL = 0x20,
|
||||
UBIFS_CRYPT_FL = 0x40,
|
||||
};
|
||||
|
||||
/* Inode flag bits used by UBIFS */
|
||||
@ -409,12 +418,19 @@ enum {
|
||||
*
|
||||
* UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
|
||||
* UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
|
||||
* UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
|
||||
* support 64bit cookies for lookups by hash
|
||||
* UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
|
||||
*/
|
||||
enum {
|
||||
UBIFS_FLG_BIGLPT = 0x02,
|
||||
UBIFS_FLG_SPACE_FIXUP = 0x04,
|
||||
UBIFS_FLG_DOUBLE_HASH = 0x08,
|
||||
UBIFS_FLG_ENCRYPTION = 0x10,
|
||||
};
|
||||
|
||||
#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION)
|
||||
|
||||
/**
|
||||
* struct ubifs_ch - common header node.
|
||||
* @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
|
||||
@ -521,7 +537,8 @@ struct ubifs_ino_node {
|
||||
* @padding1: reserved for future, zeroes
|
||||
* @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
|
||||
* @nlen: name length
|
||||
* @padding2: reserved for future, zeroes
|
||||
* @cookie: A 32bits random number, used to construct a 64bits
|
||||
* identifier.
|
||||
* @name: zero-terminated name
|
||||
*
|
||||
* Note, do not forget to amend 'zero_dent_node_unused()' function when
|
||||
@ -534,7 +551,7 @@ struct ubifs_dent_node {
|
||||
__u8 padding1;
|
||||
__u8 type;
|
||||
__le16 nlen;
|
||||
__u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
|
||||
__le32 cookie;
|
||||
__u8 name[];
|
||||
} __packed;
|
||||
|
||||
@ -544,18 +561,16 @@ struct ubifs_dent_node {
|
||||
* @key: node key
|
||||
* @size: uncompressed data size in bytes
|
||||
* @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
|
||||
* @padding: reserved for future, zeroes
|
||||
* @compr_size: compressed data size in bytes, only valid when data is encrypted
|
||||
* @data: data
|
||||
*
|
||||
* Note, do not forget to amend 'zero_data_node_unused()' function when
|
||||
* changing the padding fields.
|
||||
*/
|
||||
struct ubifs_data_node {
|
||||
struct ubifs_ch ch;
|
||||
__u8 key[UBIFS_MAX_KEY_LEN];
|
||||
__le32 size;
|
||||
__le16 compr_type;
|
||||
__u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
|
||||
__le16 compr_size;
|
||||
__u8 data[];
|
||||
} __packed;
|
||||
|
||||
|
115
fs/ubifs/ubifs.h
115
fs/ubifs/ubifs.h
@ -38,6 +38,8 @@
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/fscrypto.h>
|
||||
#include <linux/random.h>
|
||||
#include "ubifs-media.h"
|
||||
|
||||
/* Version of this UBIFS implementation */
|
||||
@ -83,10 +85,6 @@
|
||||
*/
|
||||
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
|
||||
|
||||
/* Write-buffer synchronization timeout interval in seconds */
|
||||
#define WBUF_TIMEOUT_SOFTLIMIT 3
|
||||
#define WBUF_TIMEOUT_HARDLIMIT 5
|
||||
|
||||
/* Maximum possible inode number (only 32-bit inodes are supported now) */
|
||||
#define MAX_INUM 0xFFFFFFFF
|
||||
|
||||
@ -138,6 +136,12 @@
|
||||
*/
|
||||
#define WORST_COMPR_FACTOR 2
|
||||
|
||||
#ifdef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
#define UBIFS_CIPHER_BLOCK_SIZE FS_CRYPTO_BLOCK_SIZE
|
||||
#else
|
||||
#define UBIFS_CIPHER_BLOCK_SIZE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* How much memory is needed for a buffer where we compress a data node.
|
||||
*/
|
||||
@ -645,9 +649,6 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
|
||||
* @io_mutex: serializes write-buffer I/O
|
||||
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
|
||||
* fields
|
||||
* @softlimit: soft write-buffer timeout interval
|
||||
* @delta: hard and soft timeouts delta (the timer expire interval is @softlimit
|
||||
* and @softlimit + @delta)
|
||||
* @timer: write-buffer timer
|
||||
* @no_timer: non-zero if this write-buffer does not have a timer
|
||||
* @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
|
||||
@ -676,8 +677,6 @@ struct ubifs_wbuf {
|
||||
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
|
||||
struct mutex io_mutex;
|
||||
spinlock_t lock;
|
||||
ktime_t softlimit;
|
||||
unsigned long long delta;
|
||||
struct hrtimer timer;
|
||||
unsigned int no_timer:1;
|
||||
unsigned int need_sync:1;
|
||||
@ -1007,6 +1006,8 @@ struct ubifs_debug_info;
|
||||
*
|
||||
* @big_lpt: flag that LPT is too big to write whole during commit
|
||||
* @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
|
||||
* @double_hash: flag indicating that we can do lookups by hash
|
||||
* @encrypted: flag indicating that this file system contains encrypted files
|
||||
* @no_chk_data_crc: do not check CRCs when reading data nodes (except during
|
||||
* recovery)
|
||||
* @bulk_read: enable bulk-reads
|
||||
@ -1249,6 +1250,8 @@ struct ubifs_info {
|
||||
|
||||
unsigned int big_lpt:1;
|
||||
unsigned int space_fixup:1;
|
||||
unsigned int double_hash:1;
|
||||
unsigned int encrypted:1;
|
||||
unsigned int no_chk_data_crc:1;
|
||||
unsigned int bulk_read:1;
|
||||
unsigned int default_compr:2;
|
||||
@ -1515,25 +1518,29 @@ int ubifs_consolidate_log(struct ubifs_info *c);
|
||||
|
||||
/* journal.c */
|
||||
int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
|
||||
const struct qstr *nm, const struct inode *inode,
|
||||
const struct fscrypt_name *nm, const struct inode *inode,
|
||||
int deletion, int xent);
|
||||
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
|
||||
const union ubifs_key *key, const void *buf, int len);
|
||||
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
|
||||
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
|
||||
int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
|
||||
const struct dentry *fst_dentry,
|
||||
const struct inode *fst_inode,
|
||||
const struct fscrypt_name *fst_nm,
|
||||
const struct inode *snd_dir,
|
||||
const struct dentry *snd_dentry, int sync);
|
||||
const struct inode *snd_inode,
|
||||
const struct fscrypt_name *snd_nm, int sync);
|
||||
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
|
||||
const struct dentry *old_dentry,
|
||||
const struct inode *old_inode,
|
||||
const struct fscrypt_name *old_nm,
|
||||
const struct inode *new_dir,
|
||||
const struct dentry *new_dentry,
|
||||
const struct inode *new_inode,
|
||||
const struct fscrypt_name *new_nm,
|
||||
const struct inode *whiteout, int sync);
|
||||
int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
|
||||
loff_t old_size, loff_t new_size);
|
||||
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
|
||||
const struct inode *inode, const struct qstr *nm);
|
||||
const struct inode *inode, const struct fscrypt_name *nm);
|
||||
int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
|
||||
const struct inode *inode2);
|
||||
|
||||
@ -1568,7 +1575,9 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
|
||||
int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
|
||||
struct ubifs_znode **zn, int *n);
|
||||
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
void *node, const struct qstr *nm);
|
||||
void *node, const struct fscrypt_name *nm);
|
||||
int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
|
||||
void *node, uint32_t secondary_hash);
|
||||
int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
|
||||
void *node, int *lnum, int *offs);
|
||||
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
|
||||
@ -1576,16 +1585,16 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
|
||||
int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
|
||||
int old_lnum, int old_offs, int lnum, int offs, int len);
|
||||
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
int lnum, int offs, int len, const struct qstr *nm);
|
||||
int lnum, int offs, int len, const struct fscrypt_name *nm);
|
||||
int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
|
||||
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
|
||||
const struct qstr *nm);
|
||||
const struct fscrypt_name *nm);
|
||||
int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
|
||||
union ubifs_key *to_key);
|
||||
int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
|
||||
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
|
||||
union ubifs_key *key,
|
||||
const struct qstr *nm);
|
||||
const struct fscrypt_name *nm);
|
||||
void ubifs_tnc_close(struct ubifs_info *c);
|
||||
int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
|
||||
int lnum, int offs, int is_idx);
|
||||
@ -1642,6 +1651,7 @@ int ubifs_read_superblock(struct ubifs_info *c);
|
||||
struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
|
||||
int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
|
||||
int ubifs_fixup_free_space(struct ubifs_info *c);
|
||||
int ubifs_enable_encryption(struct ubifs_info *c);
|
||||
|
||||
/* replay.c */
|
||||
int ubifs_validate_entry(struct ubifs_info *c,
|
||||
@ -1733,16 +1743,21 @@ int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
|
||||
#endif
|
||||
|
||||
/* dir.c */
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
|
||||
struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
|
||||
umode_t mode);
|
||||
int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
|
||||
struct kstat *stat);
|
||||
int ubifs_check_dir_empty(struct inode *dir);
|
||||
|
||||
/* xattr.c */
|
||||
extern const struct xattr_handler *ubifs_xattr_handlers[];
|
||||
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
|
||||
int ubifs_init_security(struct inode *dentry, struct inode *inode,
|
||||
const struct qstr *qstr);
|
||||
int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
|
||||
size_t size);
|
||||
|
||||
/* super.c */
|
||||
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
|
||||
@ -1781,6 +1796,66 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
|
||||
#include "misc.h"
|
||||
#include "key.h"
|
||||
|
||||
#ifndef CONFIG_UBIFS_FS_ENCRYPTION
|
||||
#define fscrypt_set_d_op(i)
|
||||
#define fscrypt_get_ctx fscrypt_notsupp_get_ctx
|
||||
#define fscrypt_release_ctx fscrypt_notsupp_release_ctx
|
||||
#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page
|
||||
#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page
|
||||
#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages
|
||||
#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page
|
||||
#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page
|
||||
#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range
|
||||
#define fscrypt_ioctl_set_policy fscrypt_notsupp_ioctl_set_policy
|
||||
#define fscrypt_ioctl_get_policy fscrypt_notsupp_ioctl_get_policy
|
||||
#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context
|
||||
#define fscrypt_inherit_context fscrypt_notsupp_inherit_context
|
||||
#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info
|
||||
#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info
|
||||
#define fscrypt_setup_filename fscrypt_notsupp_setup_filename
|
||||
#define fscrypt_free_filename fscrypt_notsupp_free_filename
|
||||
#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size
|
||||
#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer
|
||||
#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer
|
||||
#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr
|
||||
#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk
|
||||
static inline int ubifs_encrypt(const struct inode *inode,
|
||||
struct ubifs_data_node *dn,
|
||||
unsigned int in_len, unsigned int *out_len,
|
||||
int block)
|
||||
{
|
||||
ubifs_assert(0);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int ubifs_decrypt(const struct inode *inode,
|
||||
struct ubifs_data_node *dn,
|
||||
unsigned int *out_len, int block)
|
||||
{
|
||||
ubifs_assert(0);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#else
|
||||
/* crypto.c */
|
||||
int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
unsigned int in_len, unsigned int *out_len, int block);
|
||||
int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
|
||||
unsigned int *out_len, int block);
|
||||
#endif
|
||||
|
||||
extern struct fscrypt_operations ubifs_crypt_operations;
|
||||
|
||||
static inline bool __ubifs_crypt_is_encrypted(struct inode *inode)
|
||||
{
|
||||
struct ubifs_inode *ui = ubifs_inode(inode);
|
||||
|
||||
return ui->flags & UBIFS_CRYPT_FL;
|
||||
}
|
||||
|
||||
static inline bool ubifs_crypt_is_encrypted(const struct inode *inode)
|
||||
{
|
||||
return __ubifs_crypt_is_encrypted((struct inode *)inode);
|
||||
}
|
||||
|
||||
/* Normal UBIFS messages */
|
||||
__printf(2, 3)
|
||||
void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
|
||||
|
114
fs/ubifs/xattr.c
114
fs/ubifs/xattr.c
@ -97,7 +97,7 @@ static const struct file_operations empty_fops;
|
||||
* of failure.
|
||||
*/
|
||||
static int create_xattr(struct ubifs_info *c, struct inode *host,
|
||||
const struct qstr *nm, const void *value, int size)
|
||||
const struct fscrypt_name *nm, const void *value, int size)
|
||||
{
|
||||
int err, names_len;
|
||||
struct inode *inode;
|
||||
@ -117,7 +117,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
|
||||
* extended attributes if the name list becomes larger. This limitation
|
||||
* is artificial for UBIFS, though.
|
||||
*/
|
||||
names_len = host_ui->xattr_names + host_ui->xattr_cnt + nm->len + 1;
|
||||
names_len = host_ui->xattr_names + host_ui->xattr_cnt + fname_len(nm) + 1;
|
||||
if (names_len > XATTR_LIST_MAX) {
|
||||
ubifs_err(c, "cannot add one more xattr name to inode %lu, total names length would become %d, max. is %d",
|
||||
host->i_ino, names_len, XATTR_LIST_MAX);
|
||||
@ -154,9 +154,18 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
|
||||
mutex_lock(&host_ui->ui_mutex);
|
||||
host->i_ctime = ubifs_current_time(host);
|
||||
host_ui->xattr_cnt += 1;
|
||||
host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
|
||||
host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
|
||||
host_ui->xattr_size += CALC_XATTR_BYTES(size);
|
||||
host_ui->xattr_names += nm->len;
|
||||
host_ui->xattr_names += fname_len(nm);
|
||||
|
||||
/*
|
||||
* We handle UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT here because we
|
||||
* have to set the UBIFS_CRYPT_FL flag on the host inode.
|
||||
* To avoid multiple updates of the same inode in the same operation,
|
||||
* let's do it here.
|
||||
*/
|
||||
if (strcmp(fname_name(nm), UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
|
||||
host_ui->flags |= UBIFS_CRYPT_FL;
|
||||
|
||||
err = ubifs_jnl_update(c, host, nm, inode, 0, 1);
|
||||
if (err)
|
||||
@ -170,9 +179,10 @@ static int create_xattr(struct ubifs_info *c, struct inode *host,
|
||||
|
||||
out_cancel:
|
||||
host_ui->xattr_cnt -= 1;
|
||||
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
|
||||
host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
|
||||
host_ui->xattr_size -= CALC_XATTR_BYTES(size);
|
||||
host_ui->xattr_names -= nm->len;
|
||||
host_ui->xattr_names -= fname_len(nm);
|
||||
host_ui->flags &= ~UBIFS_CRYPT_FL;
|
||||
mutex_unlock(&host_ui->ui_mutex);
|
||||
out_free:
|
||||
make_bad_inode(inode);
|
||||
@ -269,22 +279,28 @@ static struct inode *iget_xattr(struct ubifs_info *c, ino_t inum)
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
static int __ubifs_setxattr(struct inode *host, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct ubifs_info *c = host->i_sb->s_fs_info;
|
||||
struct qstr nm = QSTR_INIT(name, strlen(name));
|
||||
struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
|
||||
struct ubifs_dent_node *xent;
|
||||
union ubifs_key key;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* Creating an encryption context is done unlocked since we
|
||||
* operate on a new inode which is not visible to other users
|
||||
* at this point.
|
||||
*/
|
||||
if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) != 0)
|
||||
ubifs_assert(inode_is_locked(host));
|
||||
|
||||
if (size > UBIFS_MAX_INO_DATA)
|
||||
return -ERANGE;
|
||||
|
||||
if (nm.len > UBIFS_MAX_NLEN)
|
||||
if (fname_len(&nm) > UBIFS_MAX_NLEN)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
|
||||
@ -329,18 +345,18 @@ out_free:
|
||||
return err;
|
||||
}
|
||||
|
||||
static ssize_t __ubifs_getxattr(struct inode *host, const char *name,
|
||||
void *buf, size_t size)
|
||||
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
|
||||
size_t size)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct ubifs_info *c = host->i_sb->s_fs_info;
|
||||
struct qstr nm = QSTR_INIT(name, strlen(name));
|
||||
struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
|
||||
struct ubifs_inode *ui;
|
||||
struct ubifs_dent_node *xent;
|
||||
union ubifs_key key;
|
||||
int err;
|
||||
|
||||
if (nm.len > UBIFS_MAX_NLEN)
|
||||
if (fname_len(&nm) > UBIFS_MAX_NLEN)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
|
||||
@ -387,6 +403,20 @@ out_unlock:
|
||||
return err;
|
||||
}
|
||||
|
||||
static bool xattr_visible(const char *name)
|
||||
{
|
||||
/* File encryption related xattrs are for internal use only */
|
||||
if (strcmp(name, UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
|
||||
return false;
|
||||
|
||||
/* Show trusted namespace only for "power" users */
|
||||
if (strncmp(name, XATTR_TRUSTED_PREFIX,
|
||||
XATTR_TRUSTED_PREFIX_LEN) == 0 && !capable(CAP_SYS_ADMIN))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
{
|
||||
union ubifs_key key;
|
||||
@ -395,7 +425,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
struct ubifs_inode *host_ui = ubifs_inode(host);
|
||||
struct ubifs_dent_node *xent, *pxent = NULL;
|
||||
int err, len, written = 0;
|
||||
struct qstr nm = { .name = NULL };
|
||||
struct fscrypt_name nm = {0};
|
||||
|
||||
dbg_gen("ino %lu ('%pd'), buffer size %zd", host->i_ino,
|
||||
dentry, size);
|
||||
@ -419,15 +449,12 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
break;
|
||||
}
|
||||
|
||||
nm.name = xent->name;
|
||||
nm.len = le16_to_cpu(xent->nlen);
|
||||
fname_name(&nm) = xent->name;
|
||||
fname_len(&nm) = le16_to_cpu(xent->nlen);
|
||||
|
||||
/* Show trusted namespace only for "power" users */
|
||||
if (strncmp(xent->name, XATTR_TRUSTED_PREFIX,
|
||||
XATTR_TRUSTED_PREFIX_LEN) ||
|
||||
capable(CAP_SYS_ADMIN)) {
|
||||
memcpy(buffer + written, nm.name, nm.len + 1);
|
||||
written += nm.len + 1;
|
||||
if (xattr_visible(xent->name)) {
|
||||
memcpy(buffer + written, fname_name(&nm), fname_len(&nm) + 1);
|
||||
written += fname_len(&nm) + 1;
|
||||
}
|
||||
|
||||
kfree(pxent);
|
||||
@ -446,7 +473,7 @@ ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
}
|
||||
|
||||
static int remove_xattr(struct ubifs_info *c, struct inode *host,
|
||||
struct inode *inode, const struct qstr *nm)
|
||||
struct inode *inode, const struct fscrypt_name *nm)
|
||||
{
|
||||
int err;
|
||||
struct ubifs_inode *host_ui = ubifs_inode(host);
|
||||
@ -463,9 +490,9 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
|
||||
mutex_lock(&host_ui->ui_mutex);
|
||||
host->i_ctime = ubifs_current_time(host);
|
||||
host_ui->xattr_cnt -= 1;
|
||||
host_ui->xattr_size -= CALC_DENT_SIZE(nm->len);
|
||||
host_ui->xattr_size -= CALC_DENT_SIZE(fname_len(nm));
|
||||
host_ui->xattr_size -= CALC_XATTR_BYTES(ui->data_len);
|
||||
host_ui->xattr_names -= nm->len;
|
||||
host_ui->xattr_names -= fname_len(nm);
|
||||
|
||||
err = ubifs_jnl_delete_xattr(c, host, inode, nm);
|
||||
if (err)
|
||||
@ -477,27 +504,27 @@ static int remove_xattr(struct ubifs_info *c, struct inode *host,
|
||||
|
||||
out_cancel:
|
||||
host_ui->xattr_cnt += 1;
|
||||
host_ui->xattr_size += CALC_DENT_SIZE(nm->len);
|
||||
host_ui->xattr_size += CALC_DENT_SIZE(fname_len(nm));
|
||||
host_ui->xattr_size += CALC_XATTR_BYTES(ui->data_len);
|
||||
host_ui->xattr_names += nm->len;
|
||||
host_ui->xattr_names += fname_len(nm);
|
||||
mutex_unlock(&host_ui->ui_mutex);
|
||||
ubifs_release_budget(c, &req);
|
||||
make_bad_inode(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __ubifs_removexattr(struct inode *host, const char *name)
|
||||
static int ubifs_xattr_remove(struct inode *host, const char *name)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct ubifs_info *c = host->i_sb->s_fs_info;
|
||||
struct qstr nm = QSTR_INIT(name, strlen(name));
|
||||
struct fscrypt_name nm = { .disk_name = FSTR_INIT((char *)name, strlen(name))};
|
||||
struct ubifs_dent_node *xent;
|
||||
union ubifs_key key;
|
||||
int err;
|
||||
|
||||
ubifs_assert(inode_is_locked(host));
|
||||
|
||||
if (nm.len > UBIFS_MAX_NLEN)
|
||||
if (fname_len(&nm) > UBIFS_MAX_NLEN)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
xent = kmalloc(UBIFS_MAX_XENT_NODE_SZ, GFP_NOFS);
|
||||
@ -548,7 +575,8 @@ static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
|
||||
}
|
||||
strcpy(name, XATTR_SECURITY_PREFIX);
|
||||
strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name);
|
||||
err = __ubifs_setxattr(inode, name, xattr->value, xattr->value_len, 0);
|
||||
err = ubifs_xattr_set(inode, name, xattr->value,
|
||||
xattr->value_len, 0);
|
||||
kfree(name);
|
||||
if (err < 0)
|
||||
break;
|
||||
@ -572,7 +600,7 @@ int ubifs_init_security(struct inode *dentry, struct inode *inode,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ubifs_xattr_get(const struct xattr_handler *handler,
|
||||
static int xattr_get(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
@ -580,10 +608,10 @@ static int ubifs_xattr_get(const struct xattr_handler *handler,
|
||||
inode->i_ino, dentry, size);
|
||||
|
||||
name = xattr_full_name(handler, name);
|
||||
return __ubifs_getxattr(inode, name, buffer, size);
|
||||
return ubifs_xattr_get(inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int ubifs_xattr_set(const struct xattr_handler *handler,
|
||||
static int xattr_set(const struct xattr_handler *handler,
|
||||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
@ -594,27 +622,27 @@ static int ubifs_xattr_set(const struct xattr_handler *handler,
|
||||
name = xattr_full_name(handler, name);
|
||||
|
||||
if (value)
|
||||
return __ubifs_setxattr(inode, name, value, size, flags);
|
||||
return ubifs_xattr_set(inode, name, value, size, flags);
|
||||
else
|
||||
return __ubifs_removexattr(inode, name);
|
||||
return ubifs_xattr_remove(inode, name);
|
||||
}
|
||||
|
||||
static const struct xattr_handler ubifs_user_xattr_handler = {
|
||||
.prefix = XATTR_USER_PREFIX,
|
||||
.get = ubifs_xattr_get,
|
||||
.set = ubifs_xattr_set,
|
||||
.get = xattr_get,
|
||||
.set = xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler ubifs_trusted_xattr_handler = {
|
||||
.prefix = XATTR_TRUSTED_PREFIX,
|
||||
.get = ubifs_xattr_get,
|
||||
.set = ubifs_xattr_set,
|
||||
.get = xattr_get,
|
||||
.set = xattr_set,
|
||||
};
|
||||
|
||||
static const struct xattr_handler ubifs_security_xattr_handler = {
|
||||
.prefix = XATTR_SECURITY_PREFIX,
|
||||
.get = ubifs_xattr_get,
|
||||
.set = ubifs_xattr_set,
|
||||
.get = xattr_get,
|
||||
.set = xattr_set,
|
||||
};
|
||||
|
||||
const struct xattr_handler *ubifs_xattr_handlers[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user