Whamcloud - gitweb
LU-12275 sec: encryption support for DoM files
[fs/lustre-release.git] / lustre / llite / file.c
index 5a543da..f411a71 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/falloc.h>
 
 #include <uapi/linux/lustre/lustre_ioctl.h>
+#include <uapi/linux/llcrypt.h>
 #include <lustre_swab.h>
 
 #include "cl_object.h"
@@ -422,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);
@@ -431,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,
@@ -474,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);
@@ -1477,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;
 
@@ -1515,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. */
@@ -1553,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 */
@@ -1563,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,
@@ -2255,6 +2300,13 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file,
                        GOTO(out, rc);
 
                rc = ll_file_getstripe(inode, arg, lum_size);
+               if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode) &&
+                   ll_i2info(inode)->lli_clob) {
+                       struct iattr attr = { 0 };
+
+                       rc = cl_setattr_ost(ll_i2info(inode)->lli_clob, &attr,
+                                           OP_XVALID_FLAGS, LUSTRE_ENCRYPT_FL);
+               }
        }
        cl_lov_delay_create_clear(&file->f_flags);
 
@@ -3988,6 +4040,33 @@ out_state:
                OBD_FREE_PTR(state);
                RETURN(rc);
        }
+#ifdef HAVE_LUSTRE_CRYPTO
+       case LL_IOC_SET_ENCRYPTION_POLICY:
+               if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+                       return -EOPNOTSUPP;
+               return llcrypt_ioctl_set_policy(file, (const void __user *)arg);
+       case LL_IOC_GET_ENCRYPTION_POLICY_EX:
+               if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+                       return -EOPNOTSUPP;
+               return llcrypt_ioctl_get_policy_ex(file, (void __user *)arg);
+       case LL_IOC_ADD_ENCRYPTION_KEY:
+               if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+                       return -EOPNOTSUPP;
+               return llcrypt_ioctl_add_key(file, (void __user *)arg);
+       case LL_IOC_REMOVE_ENCRYPTION_KEY:
+               if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+                       return -EOPNOTSUPP;
+               return llcrypt_ioctl_remove_key(file, (void __user *)arg);
+       case LL_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS:
+               if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+                       return -EOPNOTSUPP;
+               return llcrypt_ioctl_remove_key_all_users(file,
+                                                         (void __user *)arg);
+       case LL_IOC_GET_ENCRYPTION_KEY_STATUS:
+               if (!ll_sbi_has_encrypt(ll_i2sbi(inode)))
+                       return -EOPNOTSUPP;
+               return llcrypt_ioctl_get_key_status(file, (void __user *)arg);
+#endif
        default:
                RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL,
                                     (void __user *)arg));
@@ -4630,8 +4709,8 @@ static int ll_inode_revalidate(struct dentry *dentry, enum ldlm_intent_flags op)
               PFID(ll_inode2fid(inode)), inode, dentry->d_name.name);
 
        /* Call getattr by fid, so do not provide name at all. */
-       op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0,
-                                    LUSTRE_OPC_ANY, NULL);
+       op_data = ll_prep_md_op_data(NULL, dentry->d_parent->d_inode, inode,
+                                    NULL, 0, 0, LUSTRE_OPC_ANY, NULL);
        if (IS_ERR(op_data))
                RETURN(PTR_ERR(op_data));
 
@@ -4677,7 +4756,7 @@ static int ll_merge_md_attr(struct inode *inode)
                RETURN(0);
 
        down_read(&lli->lli_lsm_sem);
-       rc = md_merge_attr(ll_i2mdexp(inode), ll_i2info(inode)->lli_lsm_md,
+       rc = md_merge_attr(ll_i2mdexp(inode), &lli->lli_fid, lli->lli_lsm_md,
                           &attr, ll_md_blocking_ast);
        up_read(&lli->lli_lsm_sem);
        if (rc != 0)