diff options
Diffstat (limited to 'fs/ubifs/journal.c')
| -rw-r--r-- | fs/ubifs/journal.c | 226 | 
1 files changed, 130 insertions, 96 deletions
| diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 91bc76dc559e..294519b98874 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -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,19 @@ 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; +		out_len = compr_len; +	}  	dlen = UBIFS_DATA_NODE_SZ + out_len;  	data->compr_type = cpu_to_le16(compr_type); @@ -911,9 +924,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 +937,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 +978,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 +1019,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 +1078,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 +1128,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 +1150,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 +1194,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 +1212,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,35 +1267,60 @@ 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 (err) -		goto out; -	ubifs_compress(c, buf, *new_len, &dn->data, &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);  	*new_len = UBIFS_DATA_NODE_SZ + out_len; +	err = 0;  out:  	kfree(buf);  	return err; @@ -1347,17 +1388,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); -					if (err) -						goto out_free; -				} else { -					dn->size = cpu_to_le32(dlen); -					dlen += UBIFS_DATA_NODE_SZ; -				} -				zero_data_node_unused(dn); +				err = truncate_data_node(c, inode, blk, dn, &dlen); +				if (err) +					goto out_free;  			}  		}  	} @@ -1442,7 +1475,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 +1485,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 +1495,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 +1516,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); |