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:
Amir Samuelov
2014-06-22 16:43:52 +03:00
parent b1f8e2c919
commit acc2a3b294
7 changed files with 63 additions and 23 deletions
+2 -16
View File
@@ -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;
+35 -6
View File
@@ -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;
+1
View File
@@ -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);
+15
View File
@@ -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
*/
+7
View File
@@ -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 */
/*
+1
View File
@@ -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
View File
@@ -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 */