mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-11-07 04:09:21 +00:00
platform: msm: fix PFT when using direct-io
When read/write a file using dircet-io (O_DIRECT), we can't get the inode from a bio by walking the path bio->bi_io_vec->bv_page->mapping->host since the page is anonymous and not mapped. On the other more typical cases when not using O_DIRECT, the page cache is used and the bv_page is available. Change-Id: I349cad54a978ed9919f960d55f0f95c1e53262e5 Signed-off-by: Amir Samuelov <amirs@codeaurora.org>
This commit is contained in:
parent
d86deab83a
commit
8307869921
7 changed files with 65 additions and 24 deletions
|
@ -85,7 +85,6 @@ static bool req_crypt_should_encrypt(struct req_dm_crypt_io *req)
|
|||
int ret;
|
||||
bool should_encrypt = false;
|
||||
struct bio *bio = NULL;
|
||||
struct inode *inode = NULL;
|
||||
u32 key_id = 0;
|
||||
bool is_encrypted = false;
|
||||
bool is_inplace = false;
|
||||
|
@ -95,13 +94,7 @@ static bool req_crypt_should_encrypt(struct req_dm_crypt_io *req)
|
|||
|
||||
bio = req->cloned_request->bio;
|
||||
|
||||
if (!bio->bi_io_vec || !bio->bi_io_vec->bv_page ||
|
||||
!bio->bi_io_vec->bv_page->mapping)
|
||||
return false;
|
||||
|
||||
inode = bio->bi_io_vec->bv_page->mapping->host;
|
||||
|
||||
ret = pft_get_key_index(inode, &key_id, &is_encrypted, &is_inplace);
|
||||
ret = pft_get_key_index(bio, &key_id, &is_encrypted, &is_inplace);
|
||||
/* req->key_id = key_id; @todo support more than 1 pfe key */
|
||||
if ((ret == 0) && (is_encrypted || is_inplace)) {
|
||||
should_encrypt = true;
|
||||
|
@ -119,7 +112,6 @@ static bool req_crypt_should_deccrypt(struct req_dm_crypt_io *req)
|
|||
int ret;
|
||||
bool should_deccrypt = false;
|
||||
struct bio *bio = NULL;
|
||||
struct inode *inode = NULL;
|
||||
u32 key_id = 0;
|
||||
bool is_encrypted = false;
|
||||
bool is_inplace = false;
|
||||
|
@ -129,13 +121,7 @@ static bool req_crypt_should_deccrypt(struct req_dm_crypt_io *req)
|
|||
|
||||
bio = req->cloned_request->bio;
|
||||
|
||||
if (!bio->bi_io_vec || !bio->bi_io_vec->bv_page ||
|
||||
!bio->bi_io_vec->bv_page->mapping)
|
||||
return false;
|
||||
|
||||
inode = bio->bi_io_vec->bv_page->mapping->host;
|
||||
|
||||
ret = pft_get_key_index(inode, &key_id, &is_encrypted, &is_inplace);
|
||||
ret = pft_get_key_index(bio, &key_id, &is_encrypted, &is_inplace);
|
||||
/* req->key_id = key_id; @todo support more than 1 pfe key */
|
||||
if ((ret == 0) && (is_encrypted && !is_inplace)) {
|
||||
should_deccrypt = true;
|
||||
|
|
|
@ -162,6 +162,8 @@ struct pft_device {
|
|||
/* Device Driver State */
|
||||
static struct pft_device *pft_dev;
|
||||
|
||||
static struct inode *pft_bio_get_inode(struct bio *bio);
|
||||
|
||||
/**
|
||||
* pft_is_ready() - driver is initialized and ready.
|
||||
*
|
||||
|
@ -623,10 +625,11 @@ static inline bool pft_is_inplace_file(struct file *filp)
|
|||
*
|
||||
* Return: 0 on successe, negative value on failure.
|
||||
*/
|
||||
int pft_get_key_index(struct inode *inode, u32 *key_index,
|
||||
int pft_get_key_index(struct bio *bio, u32 *key_index,
|
||||
bool *is_encrypted, bool *is_inplace)
|
||||
{
|
||||
u32 tag = 0;
|
||||
struct inode *inode = NULL;
|
||||
|
||||
if (!pft_is_ready())
|
||||
return -ENODEV;
|
||||
|
@ -634,7 +637,7 @@ int pft_get_key_index(struct inode *inode, u32 *key_index,
|
|||
if (!selinux_is_enabled())
|
||||
return -ENODEV;
|
||||
|
||||
if (!inode)
|
||||
if (!bio)
|
||||
return -EPERM;
|
||||
|
||||
if (!is_encrypted) {
|
||||
|
@ -650,6 +653,10 @@ int pft_get_key_index(struct inode *inode, u32 *key_index,
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
inode = pft_bio_get_inode(bio);
|
||||
if (!inode)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pft_is_tag_valid(inode)) {
|
||||
pr_debug("file %s, Tag not valid\n", inode_to_filename(inode));
|
||||
return -EINVAL;
|
||||
|
@ -685,8 +692,27 @@ EXPORT_SYMBOL(pft_get_key_index);
|
|||
*/
|
||||
static struct inode *pft_bio_get_inode(struct bio *bio)
|
||||
{
|
||||
if (!bio || !bio->bi_io_vec || !bio->bi_io_vec->bv_page ||
|
||||
!bio->bi_io_vec->bv_page->mapping)
|
||||
if (!bio)
|
||||
return NULL;
|
||||
if (!bio->bi_io_vec)
|
||||
return NULL;
|
||||
if (!bio->bi_io_vec->bv_page)
|
||||
return NULL;
|
||||
|
||||
if (PageAnon(bio->bi_io_vec->bv_page)) {
|
||||
struct inode *inode;
|
||||
|
||||
/* Using direct-io (O_DIRECT) without page cache */
|
||||
inode = dio_bio_get_inode(bio);
|
||||
pr_debug("inode on direct-io, inode = 0x%x.\n", (int) inode);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
||||
if (!bio->bi_io_vec->bv_page->mapping)
|
||||
return NULL;
|
||||
|
||||
if (!bio->bi_io_vec->bv_page->mapping->host)
|
||||
return NULL;
|
||||
|
||||
return bio->bi_io_vec->bv_page->mapping->host;
|
||||
|
@ -715,12 +741,12 @@ bool pft_allow_merge_bio(struct bio *bio1, struct bio *bio2)
|
|||
if (!pft_is_ready())
|
||||
return true;
|
||||
|
||||
ret = pft_get_key_index(pft_bio_get_inode(bio1), &key_index1,
|
||||
ret = pft_get_key_index(bio1, &key_index1,
|
||||
&is_encrypted1, &is_inplace);
|
||||
if (ret)
|
||||
is_encrypted1 = false;
|
||||
|
||||
ret = pft_get_key_index(pft_bio_get_inode(bio2), &key_index2,
|
||||
ret = pft_get_key_index(bio2, &key_index2,
|
||||
&is_encrypted2, &is_inplace);
|
||||
if (ret)
|
||||
is_encrypted2 = false;
|
||||
|
@ -929,6 +955,9 @@ int pft_file_open(struct file *filp, const struct cred *cred)
|
|||
if (!pft_is_ready())
|
||||
return 0;
|
||||
|
||||
if (filp->f_flags & O_DIRECT)
|
||||
pr_debug("file %s using O_DIRECT.\n", file_to_filename(filp));
|
||||
|
||||
/* do nothing for non-encrypted files */
|
||||
if (!pft_is_encrypted_file(filp->f_dentry))
|
||||
return 0;
|
||||
|
|
1
fs/bio.c
1
fs/bio.c
|
@ -540,6 +540,7 @@ void __bio_clone(struct bio *bio, struct bio *bio_src)
|
|||
bio->bi_vcnt = bio_src->bi_vcnt;
|
||||
bio->bi_size = bio_src->bi_size;
|
||||
bio->bi_idx = bio_src->bi_idx;
|
||||
bio->bi_dio_inode = bio_src->bi_dio_inode;
|
||||
}
|
||||
EXPORT_SYMBOL(__bio_clone);
|
||||
|
||||
|
|
|
@ -380,6 +380,8 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
|
|||
if (dio->is_async && dio->rw == READ)
|
||||
bio_set_pages_dirty(bio);
|
||||
|
||||
bio->bi_dio_inode = dio->inode;
|
||||
|
||||
if (sdio->submit_io)
|
||||
sdio->submit_io(dio->rw, bio, dio->inode,
|
||||
sdio->logical_offset_in_bio);
|
||||
|
@ -391,6 +393,19 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
|
|||
sdio->logical_offset_in_bio = 0;
|
||||
}
|
||||
|
||||
struct inode *dio_bio_get_inode(struct bio *bio)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
|
||||
if (bio == NULL)
|
||||
return NULL;
|
||||
|
||||
inode = bio->bi_dio_inode;
|
||||
|
||||
return inode;
|
||||
}
|
||||
EXPORT_SYMBOL(dio_bio_get_inode);
|
||||
|
||||
/*
|
||||
* Release any resources in case of a failure
|
||||
*/
|
||||
|
|
|
@ -74,6 +74,13 @@ struct bio {
|
|||
struct bio_integrity_payload *bi_integrity; /* data integrity */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* When using dircet-io (O_DIRECT), we can't get the inode from a bio
|
||||
* by walking bio->bi_io_vec->bv_page->mapping->host
|
||||
* since the page is anon.
|
||||
*/
|
||||
struct inode *bi_dio_inode;
|
||||
|
||||
/*
|
||||
* Everything starting with bi_max_vecs will be preserved by bio_reset()
|
||||
*/
|
||||
|
|
|
@ -2455,6 +2455,7 @@ enum {
|
|||
|
||||
void dio_end_io(struct bio *bio, int error);
|
||||
|
||||
|
||||
ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
struct block_device *bdev, const struct iovec *iov, loff_t offset,
|
||||
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
|
||||
|
@ -2472,6 +2473,7 @@ static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
|
|||
|
||||
void inode_dio_wait(struct inode *inode);
|
||||
void inode_dio_done(struct inode *inode);
|
||||
struct inode *dio_bio_get_inode(struct bio *bio);
|
||||
|
||||
extern const struct file_operations generic_ro_fops;
|
||||
|
||||
|
|
|
@ -15,11 +15,12 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/bio.h>
|
||||
|
||||
#ifdef CONFIG_PFT
|
||||
|
||||
/* dm-req-crypt API */
|
||||
int pft_get_key_index(struct inode *inode, u32 *key_index,
|
||||
int pft_get_key_index(struct bio *bio, u32 *key_index,
|
||||
bool *is_encrypted, bool *is_inplace);
|
||||
|
||||
/* block layer API */
|
||||
|
@ -49,7 +50,7 @@ int pft_inode_set_xattr(struct dentry *dentry, const char *name);
|
|||
|
||||
|
||||
#else
|
||||
static inline int pft_get_key_index(struct inode *inode, u32 *key_index,
|
||||
static inline int pft_get_key_index(struct bio *bio, u32 *key_index,
|
||||
bool *is_encrypted, bool *is_inplace)
|
||||
{ return -ENODEV; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue