Whamcloud - gitweb
LU-12275 sec: encryption support for DoM files
[fs/lustre-release.git] / lustre / llite / file.c
index 4f5bba4..f411a71 100644 (file)
@@ -423,6 +423,9 @@ static inline int ll_dom_readpage(void *data, struct page *page)
 {
        struct niobuf_local *lnb = data;
        void *kaddr;
+       int rc = 0;
+
+       struct inode *inode = page2inode(page);
 
        kaddr = kmap_atomic(page);
        memcpy(kaddr, lnb->lnb_data, lnb->lnb_len);
@@ -432,9 +435,22 @@ static inline int ll_dom_readpage(void *data, struct page *page)
        flush_dcache_page(page);
        SetPageUptodate(page);
        kunmap_atomic(kaddr);
+
+       if (inode && IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) {
+               if (!llcrypt_has_encryption_key(inode))
+                       CDEBUG(D_SEC, "no enc key for "DFID"\n",
+                              PFID(ll_inode2fid(inode)));
+               /* decrypt only if page is not empty */
+               else if (memcmp(page_address(page),
+                               page_address(ZERO_PAGE(0)),
+                               PAGE_SIZE) != 0)
+                       rc = llcrypt_decrypt_pagecache_blocks(page,
+                                                             PAGE_SIZE,
+                                                             0);
+       }
        unlock_page(page);
 
-       return 0;
+       return rc;
 }
 
 void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
@@ -475,7 +491,8 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
         * buffer, in both cases total size should be equal to the file size.
         */
        body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
-       if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size) {
+       if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size &&
+           !(inode && IS_ENCRYPTED(inode))) {
                CERROR("%s: server returns off/len %llu/%u but size %llu\n",
                       ll_i2sbi(inode)->ll_fsname, rnb->rnb_offset,
                       rnb->rnb_len, body->mbo_dom_size);
@@ -1478,16 +1495,16 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
                   struct file *file, enum cl_io_type iot,
                   loff_t *ppos, size_t count)
 {
-       struct vvp_io           *vio = vvp_env_io(env);
-       struct inode            *inode = file_inode(file);
-       struct ll_inode_info    *lli = ll_i2info(inode);
-       struct ll_file_data     *fd  = file->private_data;
-       struct range_lock       range;
-       struct cl_io            *io;
-       ssize_t                 result = 0;
-       int                     rc = 0;
-       unsigned                retried = 0;
-       unsigned                ignore_lockless = 0;
+       struct vvp_io *vio = vvp_env_io(env);
+       struct inode *inode = file_inode(file);
+       struct ll_inode_info *lli = ll_i2info(inode);
+       struct ll_file_data *fd  = file->private_data;
+       struct range_lock range;
+       struct cl_io *io;
+       ssize_t result = 0;
+       int rc = 0;
+       unsigned int retried = 0, ignore_lockless = 0;
+       bool is_aio = false;
 
        ENTRY;
 
@@ -1516,6 +1533,13 @@ restart:
                case IO_NORMAL:
                        vio->vui_iter = args->u.normal.via_iter;
                        vio->vui_iocb = args->u.normal.via_iocb;
+                       if (file->f_flags & O_DIRECT) {
+                               if (!is_sync_kiocb(vio->vui_iocb))
+                                       is_aio = true;
+                               io->ci_aio = cl_aio_alloc(vio->vui_iocb);
+                               if (!io->ci_aio)
+                                       GOTO(out, rc = -ENOMEM);
+                       }
                        /* Direct IO reads must also take range lock,
                         * or multiple reads will try to work on the same pages
                         * See LU-6227 for details. */
@@ -1554,7 +1578,14 @@ restart:
                rc = io->ci_result;
        }
 
-       if (io->ci_nob > 0) {
+       /*
+        * In order to move forward AIO, ci_nob was increased,
+        * but that doesn't mean io have been finished, it just
+        * means io have been submited, we will always return
+        * EIOCBQUEUED to the caller, So we could only return
+        * number of bytes in non-AIO case.
+        */
+       if (io->ci_nob > 0 && !is_aio) {
                result += io->ci_nob;
                count  -= io->ci_nob;
                *ppos = io->u.ci_wr.wr.crw_pos; /* for splice */
@@ -1564,6 +1595,19 @@ restart:
                        args->u.normal.via_iter = vio->vui_iter;
        }
 out:
+       if (io->ci_aio) {
+               /**
+                * Drop one extra reference so that end_io() could be
+                * called for this IO context, we could call it after
+                * we make sure all AIO requests have been proceed.
+                */
+               cl_sync_io_note(env, &io->ci_aio->cda_sync,
+                               rc == -EIOCBQUEUED ? 0 : rc);
+               if (!is_aio) {
+                       cl_aio_free(io->ci_aio);
+                       io->ci_aio = NULL;
+               }
+       }
        cl_io_fini(env, io);
 
        CDEBUG(D_VFSTRACE,