Whamcloud - gitweb
LU-12275 sec: encryption for write path 44/36144/27
authorSebastien Buisson <sbuisson@ddn.com>
Wed, 17 Jul 2019 14:24:26 +0000 (14:24 +0000)
committerOleg Drokin <green@whamcloud.com>
Tue, 16 Jun 2020 03:53:33 +0000 (03:53 +0000)
First aspect is to make sure encryption context is properly set on
files/dirs that are created or opened/looked up.
Then encryption itself is carried out in osc_brw_prep_request(), just
before pages are added to the request to be sent. Because pages in
the page cache must hold clear text data, we have to use bounce pages
for encryption. The allocation is handled by fscrypt, and for
deallocation we call fscrypt_pullback_bio_page() and/or
fscrypt_pullback_bio_page().

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: Ieb1355bd55b6a8740e4b549d60d1f480a5abc53f
Reviewed-on: https://review.whamcloud.com/36144
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: John L. Hammond <jhammond@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
12 files changed:
lustre/include/lustre_osc.h
lustre/include/obd.h
lustre/include/obd_support.h
lustre/llite/crypto.c
lustre/llite/dir.c
lustre/llite/namei.c
lustre/llite/rw26.c
lustre/obdecho/echo.c
lustre/obdecho/echo_client.c
lustre/obdecho/echo_internal.h
lustre/osc/osc_internal.h
lustre/osc/osc_request.c

index 656b60a..b8cadb7 100644 (file)
@@ -49,6 +49,7 @@
 #include <libcfs/libcfs.h>
 #include <obd.h>
 #include <cl_object.h>
 #include <libcfs/libcfs.h>
 #include <obd.h>
 #include <cl_object.h>
+#include <lustre_crypto.h>
 
 /** \defgroup osc osc
  *  @{
 
 /** \defgroup osc osc
  *  @{
index 4e585ad..f758aae 100644 (file)
@@ -119,6 +119,11 @@ struct brw_page {
        struct page     *pg;
        u32              count;
        u32              flag;
        struct page     *pg;
        u32              count;
        u32              flag;
+       /* used for encryption: difference with offset in clear text page */
+       u16              bp_off_diff;
+       /* used for encryption: difference with count in clear text page */
+       u16              bp_count_diff;
+       u32              bp_padding;
 };
 
 struct timeout_item {
 };
 
 struct timeout_item {
@@ -1302,4 +1307,16 @@ static inline void client_adjust_max_dirty(struct client_obd *cli)
                                           1 << (20 - PAGE_SHIFT));
 }
 
                                           1 << (20 - PAGE_SHIFT));
 }
 
+static inline struct inode *page2inode(struct page *page)
+{
+       if (page->mapping) {
+               if (PageAnon(page))
+                       return NULL;
+               else
+                       return page->mapping->host;
+       } else {
+               return NULL;
+       }
+}
+
 #endif /* __OBD_H */
 #endif /* __OBD_H */
index 69477d8..2e44a06 100644 (file)
@@ -1009,4 +1009,9 @@ struct obd_heat_instance {
        __u64 ohi_count;
 };
 
        __u64 ohi_count;
 };
 
+/* Define a fixed 4096-byte encryption unit size */
+#define LUSTRE_ENCRYPTION_BLOCKBITS   12
+#define LUSTRE_ENCRYPTION_UNIT_SIZE   ((size_t)1 << LUSTRE_ENCRYPTION_BLOCKBITS)
+#define LUSTRE_ENCRYPTION_MASK        (~(LUSTRE_ENCRYPTION_UNIT_SIZE - 1))
+
 #endif
 #endif
index 5ccbedf..cdaac80 100644 (file)
@@ -85,6 +85,9 @@ static int ll_set_context(struct inode *inode, const void *ctx, size_t len,
        if (rc)
                return rc;
 
        if (rc)
                return rc;
 
+       /* used as encryption unit size */
+       if (S_ISREG(inode->i_mode))
+               inode->i_blkbits = LUSTRE_ENCRYPTION_BLOCKBITS;
        ll_update_inode_flags(inode, ext_flags);
        return 0;
 }
        ll_update_inode_flags(inode, ext_flags);
        return 0;
 }
index 1501ce0..4d37242 100644 (file)
@@ -417,6 +417,7 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
                                                  strlen(dirname)),
                },
        };
                                                  strlen(dirname)),
                },
        };
+       bool encrypt = false;
        int err;
        ENTRY;
 
        int err;
        ENTRY;
 
@@ -476,6 +477,16 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
        if (IS_ERR(op_data))
                RETURN(PTR_ERR(op_data));
 
        if (IS_ERR(op_data))
                RETURN(PTR_ERR(op_data));
 
+       if (IS_ENCRYPTED(parent) ||
+           unlikely(llcrypt_dummy_context_enabled(parent))) {
+               err = llcrypt_get_encryption_info(parent);
+               if (err)
+                       GOTO(out_op_data, err);
+               if (!llcrypt_has_encryption_key(parent))
+                       GOTO(out_op_data, err = -ENOKEY);
+               encrypt = true;
+       }
+
        if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
                /* selinux_dentry_init_security() uses dentry->d_parent and name
                 * to determine the security context for the file. So our fake
        if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
                /* selinux_dentry_init_security() uses dentry->d_parent and name
                 * to determine the security context for the file. So our fake
@@ -516,6 +527,12 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
        if (err)
                GOTO(out_inode, err);
 
        if (err)
                GOTO(out_inode, err);
 
+       if (encrypt) {
+               err = llcrypt_inherit_context(parent, inode, NULL, false);
+               if (err)
+                       GOTO(out_inode, err);
+       }
+
 out_inode:
        if (inode != NULL)
                iput(inode);
 out_inode:
        if (inode != NULL)
                iput(inode);
index a7d7779..e358e7a 100644 (file)
@@ -49,7 +49,7 @@
 
 static int ll_create_it(struct inode *dir, struct dentry *dentry,
                        struct lookup_intent *it,
 
 static int ll_create_it(struct inode *dir, struct dentry *dentry,
                        struct lookup_intent *it,
-                       void *secctx, __u32 secctxlen);
+                       void *secctx, __u32 secctxlen, bool encrypt);
 
 /* called from iget5_locked->find_inode() under inode_lock spinlock */
 static int ll_test_inode(struct inode *inode, void *opaque)
 
 /* called from iget5_locked->find_inode() under inode_lock spinlock */
 static int ll_test_inode(struct inode *inode, void *opaque)
@@ -611,7 +611,7 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request,
                               struct lookup_intent *it,
                               struct inode *parent, struct dentry **de,
                               void *secctx, __u32 secctxlen,
                               struct lookup_intent *it,
                               struct inode *parent, struct dentry **de,
                               void *secctx, __u32 secctxlen,
-                              ktime_t kstart)
+                              ktime_t kstart, bool encrypt)
 {
        struct inode             *inode = NULL;
        __u64                     bits = 0;
 {
        struct inode             *inode = NULL;
        __u64                     bits = 0;
@@ -688,6 +688,14 @@ static int ll_lookup_it_finish(struct ptlrpc_request *request,
                /* we have lookup look - unhide dentry */
                if (bits & MDS_INODELOCK_LOOKUP)
                        d_lustre_revalidate(*de);
                /* we have lookup look - unhide dentry */
                if (bits & MDS_INODELOCK_LOOKUP)
                        d_lustre_revalidate(*de);
+
+               if (encrypt) {
+                       rc = llcrypt_get_encryption_info(inode);
+                       if (rc)
+                               GOTO(out, rc);
+                       if (!llcrypt_has_encryption_key(inode))
+                               GOTO(out, rc = -ENOKEY);
+               }
        } else if (!it_disposition(it, DISP_OPEN_CREATE)) {
                /*
                 * If file was created on the server, the dentry is revalidated
        } else if (!it_disposition(it, DISP_OPEN_CREATE)) {
                /*
                 * If file was created on the server, the dentry is revalidated
@@ -735,7 +743,8 @@ out:
 static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                                   struct lookup_intent *it,
                                   void **secctx, __u32 *secctxlen,
 static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                                   struct lookup_intent *it,
                                   void **secctx, __u32 *secctxlen,
-                                  struct pcc_create_attach *pca)
+                                  struct pcc_create_attach *pca,
+                                  bool encrypt)
 {
        ktime_t kstart = ktime_get();
        struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
 {
        ktime_t kstart = ktime_get();
        struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
@@ -884,18 +893,18 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
        rc = ll_lookup_it_finish(req, it, parent, &dentry,
                                 secctx != NULL ? *secctx : NULL,
                                 secctxlen != NULL ? *secctxlen : 0,
        rc = ll_lookup_it_finish(req, it, parent, &dentry,
                                 secctx != NULL ? *secctx : NULL,
                                 secctxlen != NULL ? *secctxlen : 0,
-                               kstart);
-        if (rc != 0) {
-                ll_intent_release(it);
-                GOTO(out, retval = ERR_PTR(rc));
-        }
-
-        if ((it->it_op & IT_OPEN) && dentry->d_inode &&
-            !S_ISREG(dentry->d_inode->i_mode) &&
-            !S_ISDIR(dentry->d_inode->i_mode)) {
-                ll_release_openhandle(dentry, it);
-        }
-        ll_lookup_finish_locks(it, dentry);
+                                kstart, encrypt);
+       if (rc != 0) {
+               ll_intent_release(it);
+               GOTO(out, retval = ERR_PTR(rc));
+       }
+
+       if ((it->it_op & IT_OPEN) && dentry->d_inode &&
+           !S_ISREG(dentry->d_inode->i_mode) &&
+           !S_ISDIR(dentry->d_inode->i_mode)) {
+               ll_release_openhandle(dentry, it);
+       }
+       ll_lookup_finish_locks(it, dentry);
 
        GOTO(out, retval = (dentry == save) ? NULL : dentry);
 
 
        GOTO(out, retval = (dentry == save) ? NULL : dentry);
 
@@ -939,7 +948,7 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
                itp = NULL;
        else
                itp = &it;
                itp = NULL;
        else
                itp = &it;
-       de = ll_lookup_it(parent, dentry, itp, NULL, NULL, NULL);
+       de = ll_lookup_it(parent, dentry, itp, NULL, NULL, NULL, false);
 
        if (itp != NULL)
                ll_intent_release(itp);
 
        if (itp != NULL)
                ll_intent_release(itp);
@@ -980,8 +989,9 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
        long long lookup_flags = LOOKUP_OPEN;
        void *secctx = NULL;
        __u32 secctxlen = 0;
        long long lookup_flags = LOOKUP_OPEN;
        void *secctx = NULL;
        __u32 secctxlen = 0;
-       struct ll_sb_info *sbi;
+       struct ll_sb_info *sbi = NULL;
        struct pcc_create_attach pca = { NULL, NULL };
        struct pcc_create_attach pca = { NULL, NULL };
+       bool encrypt = false;
        int rc = 0;
        ENTRY;
 
        int rc = 0;
        ENTRY;
 
@@ -1036,8 +1046,21 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
        it->it_flags = (open_flags & ~O_ACCMODE) | OPEN_FMODE(open_flags);
        it->it_flags &= ~MDS_OPEN_FL_INTERNAL;
 
        it->it_flags = (open_flags & ~O_ACCMODE) | OPEN_FMODE(open_flags);
        it->it_flags &= ~MDS_OPEN_FL_INTERNAL;
 
+       if (IS_ENCRYPTED(dir)) {
+               /* we know that we are going to create a regular file because
+                * we set S_IFREG bit on it->it_create_mode above
+                */
+               rc = llcrypt_get_encryption_info(dir);
+               if (rc)
+                       GOTO(out_release, rc);
+               if (!llcrypt_has_encryption_key(dir))
+                       GOTO(out_release, rc = -ENOKEY);
+               encrypt = true;
+               rc = 0;
+       }
+
        /* Dentry added to dcache tree in ll_lookup_it */
        /* Dentry added to dcache tree in ll_lookup_it */
-       de = ll_lookup_it(dir, dentry, it, &secctx, &secctxlen, &pca);
+       de = ll_lookup_it(dir, dentry, it, &secctx, &secctxlen, &pca, encrypt);
        if (IS_ERR(de))
                rc = PTR_ERR(de);
        else if (de != NULL)
        if (IS_ERR(de))
                rc = PTR_ERR(de);
        else if (de != NULL)
@@ -1048,7 +1071,8 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
        if (!rc) {
                if (it_disposition(it, DISP_OPEN_CREATE)) {
                        /* Dentry instantiated in ll_create_it. */
        if (!rc) {
                if (it_disposition(it, DISP_OPEN_CREATE)) {
                        /* Dentry instantiated in ll_create_it. */
-                       rc = ll_create_it(dir, dentry, it, secctx, secctxlen);
+                       rc = ll_create_it(dir, dentry, it, secctx, secctxlen,
+                                         encrypt);
                        security_release_secctx(secctx, secctxlen);
                        if (rc) {
                                /* We dget in ll_splice_alias. */
                        security_release_secctx(secctx, secctxlen);
                        if (rc) {
                                /* We dget in ll_splice_alias. */
@@ -1161,7 +1185,7 @@ static struct inode *ll_create_node(struct inode *dir, struct lookup_intent *it)
  */
 static int ll_create_it(struct inode *dir, struct dentry *dentry,
                        struct lookup_intent *it,
  */
 static int ll_create_it(struct inode *dir, struct dentry *dentry,
                        struct lookup_intent *it,
-                       void *secctx, __u32 secctxlen)
+                       void *secctx, __u32 secctxlen, bool encrypt)
 {
        struct inode *inode;
        __u64 bits = 0;
 {
        struct inode *inode;
        __u64 bits = 0;
@@ -1193,6 +1217,12 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry,
 
        d_instantiate(dentry, inode);
 
 
        d_instantiate(dentry, inode);
 
+       if (encrypt) {
+               rc = llcrypt_inherit_context(dir, inode, dentry, true);
+               if (rc)
+                       RETURN(rc);
+       }
+
        if (!(ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX)) {
                rc = ll_inode_init_security(dentry, inode, dir);
                if (rc)
        if (!(ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX)) {
                rc = ll_inode_init_security(dentry, inode, dir);
                if (rc)
@@ -1230,16 +1260,17 @@ static int ll_new_node(struct inode *dir, struct dentry *dchild,
                       const char *tgt, umode_t mode, int rdev, __u32 opc)
 {
        struct qstr *name = &dchild->d_name;
                       const char *tgt, umode_t mode, int rdev, __u32 opc)
 {
        struct qstr *name = &dchild->d_name;
-        struct ptlrpc_request *request = NULL;
-        struct md_op_data *op_data;
-        struct inode *inode = NULL;
-        struct ll_sb_info *sbi = ll_i2sbi(dir);
-        int tgt_len = 0;
-        int err;
+       struct ptlrpc_request *request = NULL;
+       struct md_op_data *op_data = NULL;
+       struct inode *inode = NULL;
+       struct ll_sb_info *sbi = ll_i2sbi(dir);
+       int tgt_len = 0;
+       int encrypt = 0;
+       int err;
 
 
-        ENTRY;
-        if (unlikely(tgt != NULL))
-                tgt_len = strlen(tgt) + 1;
+       ENTRY;
+       if (unlikely(tgt != NULL))
+               tgt_len = strlen(tgt) + 1;
 
 again:
        op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
 
 again:
        op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
@@ -1256,6 +1287,17 @@ again:
                        GOTO(err_exit, err);
        }
 
                        GOTO(err_exit, err);
        }
 
+       if ((IS_ENCRYPTED(dir) &&
+           (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) ||
+           (unlikely(llcrypt_dummy_context_enabled(dir)) && S_ISDIR(mode))) {
+               err = llcrypt_get_encryption_info(dir);
+               if (err)
+                       GOTO(err_exit, err);
+               if (!llcrypt_has_encryption_key(dir))
+                       GOTO(err_exit, err = -ENOKEY);
+               encrypt = 1;
+       }
+
        err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
        err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
@@ -1348,6 +1390,12 @@ again:
 
        d_instantiate(dchild, inode);
 
 
        d_instantiate(dchild, inode);
 
+       if (encrypt) {
+               err = llcrypt_inherit_context(dir, inode, NULL, true);
+               if (err)
+                       GOTO(err_exit, err);
+       }
+
        if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
                err = ll_inode_init_security(dchild, inode, dir);
                if (err)
        if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
                err = ll_inode_init_security(dchild, inode, dir);
                if (err)
@@ -1362,7 +1410,7 @@ err_exit:
        if (!IS_ERR_OR_NULL(op_data))
                ll_finish_md_op_data(op_data);
 
        if (!IS_ERR_OR_NULL(op_data))
                ll_finish_md_op_data(op_data);
 
-       return err;
+       RETURN(err);
 }
 
 static int ll_mknod(struct inode *dir, struct dentry *dchild, umode_t mode,
 }
 
 static int ll_mknod(struct inode *dir, struct dentry *dchild, umode_t mode,
@@ -1470,6 +1518,10 @@ static int ll_link(struct dentry *old_dentry, struct inode *dir,
               PFID(ll_inode2fid(src)), src,
               PFID(ll_inode2fid(dir)), dir, new_dentry);
 
               PFID(ll_inode2fid(src)), src,
               PFID(ll_inode2fid(dir)), dir, new_dentry);
 
+       err = llcrypt_prepare_link(old_dentry, dir, new_dentry);
+       if (err)
+               RETURN(err);
+
        op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
                                     0, LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
        op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
                                     0, LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
@@ -1664,6 +1716,14 @@ static int ll_rename(struct inode *src, struct dentry *src_dchild,
        if (unlikely(d_mountpoint(src_dchild) || d_mountpoint(tgt_dchild)))
                RETURN(-EBUSY);
 
        if (unlikely(d_mountpoint(src_dchild) || d_mountpoint(tgt_dchild)))
                RETURN(-EBUSY);
 
+#ifdef HAVE_IOPS_RENAME_WITH_FLAGS
+       err = llcrypt_prepare_rename(src, src_dchild, tgt, tgt_dchild, flags);
+#else
+       err = llcrypt_prepare_rename(src, src_dchild, tgt, tgt_dchild, 0);
+#endif
+       if (err)
+               RETURN(err);
+
        op_data = ll_prep_md_op_data(NULL, src, tgt, NULL, 0, 0,
                                     LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
        op_data = ll_prep_md_op_data(NULL, src, tgt, NULL, 0, 0,
                                     LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
index 5c4dd7b..28b85c0 100644 (file)
@@ -399,6 +399,10 @@ ll_direct_IO_impl(struct kiocb *iocb, struct iov_iter *iter, int rw)
        ssize_t tot_bytes = 0, result = 0;
        loff_t file_offset = iocb->ki_pos;
 
        ssize_t tot_bytes = 0, result = 0;
        loff_t file_offset = iocb->ki_pos;
 
+       /* if file is encrypted, return 0 so that we fall back to buffered IO */
+       if (IS_ENCRYPTED(inode))
+               return 0;
+
        /* Check EOF by ourselves */
        if (rw == READ && file_offset >= i_size_read(inode))
                return 0;
        /* Check EOF by ourselves */
        if (rw == READ && file_offset >= i_size_read(inode))
                return 0;
index e31d048..a0675c5 100644 (file)
@@ -232,6 +232,8 @@ static int echo_map_nb_to_lb(struct obdo *oa, struct obd_ioobj *obj,
                                       POSTID(&obj->ioo_oid));
                                return -ENOMEM;
                        }
                                       POSTID(&obj->ioo_oid));
                                return -ENOMEM;
                        }
+                       /* set mapping so page is not considered encrypted */
+                       res->lnb_page->mapping = ECHO_MAPPING_UNENCRYPTED;
                }
 
                CDEBUG(D_PAGE, "$$$$ get page %p @ %llu for %d\n",
                }
 
                CDEBUG(D_PAGE, "$$$$ get page %p @ %llu for %d\n",
@@ -964,6 +966,8 @@ int echo_persistent_pages_init(void)
 
                memset(kmap(pg), 0, PAGE_SIZE);
                kunmap(pg);
 
                memset(kmap(pg), 0, PAGE_SIZE);
                kunmap(pg);
+               /* set mapping so page is not considered encrypted */
+               pg->mapping = ECHO_MAPPING_UNENCRYPTED;
 
                echo_persistent_pages[i] = pg;
        }
 
                echo_persistent_pages[i] = pg;
        }
index 19e522a..a7d3bd4 100644 (file)
@@ -2594,6 +2594,8 @@ static int echo_client_kbrw(struct echo_device *ed, int rw, struct obdo *oa,
                if (!pgp->pg)
                        goto out;
 
                if (!pgp->pg)
                        goto out;
 
+               /* set mapping so page is not considered encrypted */
+               pgp->pg->mapping = ECHO_MAPPING_UNENCRYPTED;
                pages[i] = pgp->pg;
                pgp->count = PAGE_SIZE;
                pgp->off = off;
                pages[i] = pgp->pg;
                pgp->count = PAGE_SIZE;
                pgp->off = off;
index 4462422..c1e6871 100644 (file)
@@ -50,4 +50,7 @@ int echo_persistent_pages_init(void);
 void echo_persistent_pages_fini(void);
 #endif /* HAVE_SERVER_SUPPORT */
 
 void echo_persistent_pages_fini(void);
 #endif /* HAVE_SERVER_SUPPORT */
 
+/* mapping value to tell page is not encrypted */
+#define ECHO_MAPPING_UNENCRYPTED ((void *)1)
+
 #endif
 #endif
index 4e501b8..1c38522 100644 (file)
@@ -219,4 +219,5 @@ static inline void osc_set_io_portal(struct ptlrpc_request *req)
        else
                req->rq_request_portal = OST_IO_PORTAL;
 }
        else
                req->rq_request_portal = OST_IO_PORTAL;
 }
+
 #endif /* OSC_INTERNAL_H */
 #endif /* OSC_INTERNAL_H */
index 1d9971f..fea0c94 100644 (file)
@@ -1347,28 +1347,50 @@ static int osc_checksum_bulk_rw(const char *obd_name,
        RETURN(rc);
 }
 
        RETURN(rc);
 }
 
+static inline void osc_release_bounce_pages(struct brw_page **pga,
+                                           u32 page_count)
+{
+#ifdef HAVE_LUSTRE_CRYPTO
+       int i;
+
+       for (i = 0; i < page_count; i++) {
+               if (pga[i]->pg->mapping)
+                       /* bounce pages are unmapped */
+                       continue;
+               if (pga[i]->flag & OBD_BRW_SYNC)
+                       /* sync transfer cannot have encrypted pages */
+                       continue;
+               llcrypt_finalize_bounce_page(&pga[i]->pg);
+               pga[i]->count -= pga[i]->bp_count_diff;
+               pga[i]->off += pga[i]->bp_off_diff;
+       }
+#endif
+}
+
 static int
 osc_brw_prep_request(int cmd, struct client_obd *cli, struct obdo *oa,
                     u32 page_count, struct brw_page **pga,
                     struct ptlrpc_request **reqp, int resend)
 {
 static int
 osc_brw_prep_request(int cmd, struct client_obd *cli, struct obdo *oa,
                     u32 page_count, struct brw_page **pga,
                     struct ptlrpc_request **reqp, int resend)
 {
-        struct ptlrpc_request   *req;
-        struct ptlrpc_bulk_desc *desc;
-        struct ost_body         *body;
-        struct obd_ioobj        *ioobj;
-        struct niobuf_remote    *niobuf;
+       struct ptlrpc_request *req;
+       struct ptlrpc_bulk_desc *desc;
+       struct ost_body *body;
+       struct obd_ioobj *ioobj;
+       struct niobuf_remote *niobuf;
        int niocount, i, requested_nob, opc, rc, short_io_size = 0;
        int niocount, i, requested_nob, opc, rc, short_io_size = 0;
-        struct osc_brw_async_args *aa;
-        struct req_capsule      *pill;
-        struct brw_page *pg_prev;
+       struct osc_brw_async_args *aa;
+       struct req_capsule *pill;
+       struct brw_page *pg_prev;
        void *short_io_buf;
        const char *obd_name = cli->cl_import->imp_obd->obd_name;
        void *short_io_buf;
        const char *obd_name = cli->cl_import->imp_obd->obd_name;
+       struct inode *inode;
 
 
-        ENTRY;
-        if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ))
-                RETURN(-ENOMEM); /* Recoverable */
-        if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ2))
-                RETURN(-EINVAL); /* Fatal */
+       ENTRY;
+       inode = page2inode(pga[0]->pg);
+       if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ))
+               RETURN(-ENOMEM); /* Recoverable */
+       if (OBD_FAIL_CHECK(OBD_FAIL_OSC_BRW_PREP_REQ2))
+               RETURN(-EINVAL); /* Fatal */
 
        if ((cmd & OBD_BRW_WRITE) != 0) {
                opc = OST_WRITE;
 
        if ((cmd & OBD_BRW_WRITE) != 0) {
                opc = OST_WRITE;
@@ -1382,6 +1404,51 @@ osc_brw_prep_request(int cmd, struct client_obd *cli, struct obdo *oa,
         if (req == NULL)
                 RETURN(-ENOMEM);
 
         if (req == NULL)
                 RETURN(-ENOMEM);
 
+       if (opc == OST_WRITE && inode && IS_ENCRYPTED(inode)) {
+               for (i = 0; i < page_count; i++) {
+                       struct brw_page *pg = pga[i];
+                       struct page *data_page = NULL;
+                       bool retried = false;
+                       bool lockedbymyself;
+
+retry_encrypt:
+                       /* The page can already be locked when we arrive here.
+                        * This is possible when cl_page_assume/vvp_page_assume
+                        * is stuck on wait_on_page_writeback with page lock
+                        * held. In this case there is no risk for the lock to
+                        * be released while we are doing our encryption
+                        * processing, because writeback against that page will
+                        * end in vvp_page_completion_write/cl_page_completion,
+                        * which means only once the page is fully processed.
+                        */
+                       lockedbymyself = trylock_page(pg->pg);
+                       data_page =
+                               llcrypt_encrypt_pagecache_blocks(pg->pg,
+                                                                PAGE_SIZE, 0,
+                                                                GFP_NOFS);
+                       if (lockedbymyself)
+                               unlock_page(pg->pg);
+                       if (IS_ERR(data_page)) {
+                               rc = PTR_ERR(data_page);
+                               if (rc == -ENOMEM && !retried) {
+                                       retried = true;
+                                       rc = 0;
+                                       goto retry_encrypt;
+                               }
+                               ptlrpc_request_free(req);
+                               RETURN(rc);
+                       }
+                       /* len is forced to PAGE_SIZE, and poff to 0
+                        * so store the old, clear text info
+                        */
+                       pg->pg = data_page;
+                       pg->bp_count_diff = PAGE_SIZE - pg->count;
+                       pg->count = PAGE_SIZE;
+                       pg->bp_off_diff = pg->off & ~PAGE_MASK;
+                       pg->off = pg->off & PAGE_MASK;
+               }
+       }
+
         for (niocount = i = 1; i < page_count; i++) {
                 if (!can_merge_pages(pga[i - 1], pga[i]))
                         niocount++;
         for (niocount = i = 1; i < page_count; i++) {
                 if (!can_merge_pages(pga[i - 1], pga[i]))
                         niocount++;
@@ -2096,6 +2163,10 @@ static int brw_interpret(const struct lu_env *env,
 
        rc = osc_brw_fini_request(req, rc);
        CDEBUG(D_INODE, "request %p aa %p rc %d\n", req, aa, rc);
 
        rc = osc_brw_fini_request(req, rc);
        CDEBUG(D_INODE, "request %p aa %p rc %d\n", req, aa, rc);
+
+       /* restore clear text pages */
+       osc_release_bounce_pages(aa->aa_ppga, aa->aa_page_count);
+
        /*
         * When server returns -EINPROGRESS, client should always retry
         * regardless of the number of times the bulk was resent already.
        /*
         * When server returns -EINPROGRESS, client should always retry
         * regardless of the number of times the bulk was resent already.
@@ -2404,8 +2475,10 @@ out:
 
                if (oa)
                        OBD_SLAB_FREE_PTR(oa, osc_obdo_kmem);
 
                if (oa)
                        OBD_SLAB_FREE_PTR(oa, osc_obdo_kmem);
-               if (pga)
-                       OBD_FREE_PTR_ARRAY(pga, page_count);
+               if (pga) {
+                       osc_release_bounce_pages(pga, page_count);
+                       osc_release_ppga(pga, page_count);
+               }
                /* this should happen rarely and is pretty bad, it makes the
                 * pending list not follow the dirty order */
                while (!list_empty(ext_list)) {
                /* this should happen rarely and is pretty bad, it makes the
                 * pending list not follow the dirty order */
                while (!list_empty(ext_list)) {