forked from rubenslte/android_kernel_samsung_msm8226
platform: msm: fix PFT when using direct-io
When we 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:
@@ -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.
|
||||
*
|
||||
@@ -624,10 +626,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;
|
||||
@@ -635,7 +638,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) {
|
||||
@@ -651,6 +654,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;
|
||||
@@ -686,8 +693,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;
|
||||
@@ -716,12 +742,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;
|
||||
@@ -930,6 +956,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;
|
||||
|
||||
@@ -458,6 +458,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);
|
||||
|
||||
|
||||
@@ -423,6 +423,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);
|
||||
@@ -434,6 +436,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
|
||||
*/
|
||||
|
||||
@@ -70,6 +70,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;
|
||||
|
||||
bio_destructor_t *bi_destructor; /* destructor */
|
||||
|
||||
/*
|
||||
|
||||
@@ -2436,6 +2436,7 @@ enum {
|
||||
void dio_end_io(struct bio *bio, int error);
|
||||
void inode_dio_wait(struct inode *inode);
|
||||
void inode_dio_done(struct inode *inode);
|
||||
struct inode *dio_bio_get_inode(struct bio *bio);
|
||||
|
||||
ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
||||
struct block_device *bdev, const struct iovec *iov, loff_t offset,
|
||||
|
||||
+2
-1
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user