Hi Al,
Today's linux-next merge of the vfs tree got a conflict in
fs/ext4/symlink.c between commit f1195c72c951 ("ext4 crypto: Add
symlink encryption") from the ext4 tree and commit 5dd3dc06371a ("VFS:
normal filesystems (and lustre): d_inode() annotations") from the vfs
tree.I fixed it up (see below) and can carry the fix as necessary (no action is required). P.S. is there some reason that the two copies of "EXT4_I(dentry->d_inode)" that I fixed up below are not just "EXT4_I(inode)" ? -- Cheers, Stephen Rothwell [email protected] diff --cc fs/ext4/symlink.c index 408d15bc7b12,57f50091b8d1..000000000000 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@@ -21,112 -21,11 +21,112 @@@ #include <linux/namei.h> #include "ext4.h" #include "xattr.h" +#include "ext4_crypto.h" +#ifdef CONFIG_EXT4_FS_ENCRYPTION static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd) { + struct page *cpage = NULL; + char *caddr, *paddr = NULL; + struct ext4_str cstr, pstr; - struct inode *inode = dentry->d_inode; ++ struct inode *inode = d_inode(dentry); + struct ext4_fname_crypto_ctx *ctx = NULL; + struct ext4_encrypted_symlink_data *sd; + loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); + int res; + u32 plen, plen2, max_size = inode->i_sb->s_blocksize; + + ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize); + if (IS_ERR(ctx)) + return ctx; + + if (ext4_inode_is_fast_symlink(inode)) { - caddr = (char *) EXT4_I(dentry->d_inode)->i_data; - max_size = sizeof(EXT4_I(dentry->d_inode)->i_data); ++ caddr = (char *) EXT4_I(d_inode(dentry))->i_data; ++ max_size = sizeof(EXT4_I(d_inode(dentry))->i_data); + } else { + cpage = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(cpage)) { + ext4_put_fname_crypto_ctx(&ctx); + return cpage; + } + caddr = kmap(cpage); + caddr[size] = 0; + } + + if (!ctx) { + /* Symlink is unencrypted */ + plen = strnlen((char *)caddr, inode->i_sb->s_blocksize); + plen2 = (plen < max_size) ? plen + 1 : plen; + paddr = kmalloc(plen2, GFP_NOFS); + if (!paddr) { + ext4_put_fname_crypto_ctx(&ctx); + kunmap(cpage); + page_cache_release(cpage); + return ERR_PTR(-ENOMEM); + } + memcpy(paddr, caddr, plen); + if (plen < inode->i_sb->s_blocksize) + paddr[plen] = '\0'; + } else { + /* Symlink is encrypted */ + sd = (struct ext4_encrypted_symlink_data *)caddr; + cstr.name = sd->encrypted_path; + cstr.len = le32_to_cpu(sd->len); + if ((cstr.len + + sizeof(struct ext4_encrypted_symlink_data) - 1) > + max_size) { + /* Symlink data on the disk is corrupted */ + res = -EIO; + goto errout; + } + plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ? + EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len; + paddr = kmalloc(plen + 1, GFP_NOFS); + if (!paddr) { + res = -ENOMEM; + goto errout; + } + pstr.name = paddr; + res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr); + if (res < 0) + goto errout; + /* Null-terminate the name */ + if (res <= plen) + paddr[res] = '\0'; + } + nd_set_link(nd, paddr); + ext4_put_fname_crypto_ctx(&ctx); + return cpage; +errout: + ext4_put_fname_crypto_ctx(&ctx); + if (cpage) { + kunmap(cpage); + page_cache_release(cpage); + } + kfree(paddr); + return ERR_PTR(res); +} + +static void ext4_put_link(struct dentry *dentry, struct nameidata *nd, + void *cookie) +{ + struct page *page = cookie; + char *buf = nd_get_link(nd); + + if (page) { + kunmap(page); + page_cache_release(page); + } + if (buf) { + nd_set_link(nd, NULL); + kfree(buf); + } +} +#endif + +static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd) +{ - struct ext4_inode_info *ei = EXT4_I(dentry->d_inode); + struct ext4_inode_info *ei = EXT4_I(d_inode(dentry)); nd_set_link(nd, (char *) ei->i_data); return NULL; }
pgpOJymdHRkTF.pgp
Description: OpenPGP digital signature

