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:
Amir Samuelov 2014-06-23 21:38:40 +03:00
parent d86deab83a
commit 8307869921
7 changed files with 65 additions and 24 deletions

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;

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.
*
@ -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;

View file

@ -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);

View file

@ -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
*/

View file

@ -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()
*/

View file

@ -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;

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 */
@ -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; }