Whamcloud - gitweb
LU-15216 lmv: improve MDT QOS space balance
[fs/lustre-release.git] / lustre / llite / dir.c
index 95fd4b2..4006417 100644 (file)
@@ -55,6 +55,7 @@
 #include <lustre_fid.h>
 #include <lustre_kernelcomm.h>
 #include <lustre_swab.h>
+#include <libcfs/libcfs_crypto.h>
 
 #include "llite_internal.h"
 
@@ -186,15 +187,22 @@ int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
                void *cookie, filldir_t filldir)
 {
 #endif
-       struct ll_sb_info    *sbi        = ll_i2sbi(inode);
-       __u64                 pos        = *ppos;
-       bool                  is_api32 = ll_need_32bit_api(sbi);
-       bool                  is_hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
-       struct page          *page;
-       bool                  done = false;
-       int                   rc = 0;
+       struct ll_sb_info *sbi = ll_i2sbi(inode);
+       __u64 pos = *ppos;
+       bool is_api32 = ll_need_32bit_api(sbi);
+       bool is_hash64 = test_bit(LL_SBI_64BIT_HASH, sbi->ll_flags);
+       struct page *page;
+       bool done = false;
+       struct llcrypt_str lltr = LLTR_INIT(NULL, 0);
+       int rc = 0;
        ENTRY;
 
+       if (IS_ENCRYPTED(inode)) {
+               rc = llcrypt_fname_alloc_buffer(inode, NAME_MAX, &lltr);
+               if (rc < 0)
+                       RETURN(rc);
+       }
+
        page = ll_get_dir_page(inode, op_data, pos);
 
        while (rc == 0 && !done) {
@@ -238,9 +246,31 @@ int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
                         * for 'filldir()' must be part of the 'ent'. */
 #ifdef HAVE_DIR_CONTEXT
                        ctx->pos = lhash;
-                       done = !dir_emit(ctx, ent->lde_name, namelen, ino,
-                                        type);
+                       if (!IS_ENCRYPTED(inode)) {
+                               done = !dir_emit(ctx, ent->lde_name, namelen,
+                                                ino, type);
+                       } else {
+                               /* Directory is encrypted */
+                               int save_len = lltr.len;
+                               struct llcrypt_str de_name =
+                                       LLTR_INIT(ent->lde_name, namelen);
+
+                               rc = ll_fname_disk_to_usr(inode, 0, 0, &de_name,
+                                                         &lltr, &fid);
+                               de_name = lltr;
+                               lltr.len = save_len;
+                               if (rc) {
+                                       done = 1;
+                                       break;
+                               }
+                               done = !dir_emit(ctx, de_name.name, de_name.len,
+                                                ino, type);
+                       }
 #else
+                       /* HAVE_DIR_CONTEXT is defined from kernel 3.11, whereas
+                        * IS_ENCRYPTED is brought by kernel 4.14.
+                        * So there is no need to handle encryption case here.
+                        */
                        done = filldir(cookie, ent->lde_name, namelen, lhash,
                                       ino, type);
 #endif
@@ -277,6 +307,7 @@ int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
 #else
        *ppos = pos;
 #endif
+       llcrypt_fname_free_buffer(&lltr);
        RETURN(rc);
 }
 
@@ -289,7 +320,7 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
        struct inode *inode = file_inode(filp);
        struct ll_file_data *lfd = filp->private_data;
        struct ll_sb_info *sbi = ll_i2sbi(inode);
-       int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
+       bool hash64 = test_bit(LL_SBI_64BIT_HASH, sbi->ll_flags);
        int api32 = ll_need_32bit_api(sbi);
        struct md_op_data *op_data;
        struct lu_fid pfid = { 0 };
@@ -308,6 +339,12 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
               PFID(ll_inode2fid(inode)),
               inode, (unsigned long)pos, i_size_read(inode), api32);
 
+       if (IS_ENCRYPTED(inode)) {
+               rc = llcrypt_get_encryption_info(inode);
+               if (rc && rc != -ENOKEY)
+                       GOTO(out, rc);
+       }
+
        if (pos == MDS_DIR_END_OFF)
                /*
                 * end-of-file.
@@ -416,9 +453,10 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
                },
        };
        bool encrypt = false;
+       int hash_flags;
        int err;
-       ENTRY;
 
+       ENTRY;
        if (unlikely(!lmv_user_magic_supported(lump->lum_magic)))
                RETURN(-EINVAL);
 
@@ -457,6 +495,10 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
                                              LMV_HASH_TYPE_FNV_1A_64;
        }
 
+       hash_flags = lump->lum_hash_type & ~LMV_HASH_TYPE_MASK;
+       if (hash_flags & ~LMV_HASH_FLAG_KNOWN)
+               RETURN(-EINVAL);
+
        if (unlikely(!lmv_user_magic_supported(cpu_to_le32(lump->lum_magic))))
                lustre_swab_lmv_user_md(lump);
 
@@ -469,6 +511,8 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
        if (IS_ERR(op_data))
                RETURN(PTR_ERR(op_data));
 
+       op_data->op_dir_depth = ll_i2info(parent)->lli_dir_depth;
+
        if (ll_sbi_has_encrypt(sbi) &&
            (IS_ENCRYPTED(parent) ||
            unlikely(llcrypt_dummy_context_enabled(parent)))) {
@@ -480,7 +524,7 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
                encrypt = true;
        }
 
-       if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
+       if (test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags)) {
                /* selinux_dentry_init_security() uses dentry->d_parent and name
                 * to determine the security context for the file. So our fake
                 * dentry should be real enough for this purpose. */
@@ -505,7 +549,7 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
        err = md_create(sbi->ll_md_exp, op_data, lump, len, mode,
                        from_kuid(&init_user_ns, current_fsuid()),
                        from_kgid(&init_user_ns, current_fsgid()),
-                       cfs_curproc_cap_pack(), 0, &request);
+                       current_cap(), 0, &request);
        if (err)
                GOTO(out_request, err);
 
@@ -517,7 +561,7 @@ static int ll_dir_setdirstripe(struct dentry *dparent, struct lmv_user_md *lump,
 
        dentry.d_inode = inode;
 
-       if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
+       if (test_bit(LL_SBI_FILE_SECCTX, sbi->ll_flags)) {
                /* no need to protect selinux_inode_setsecurity() by
                 * inode_lock. Taking it would lead to a client deadlock
                 * LU-13617
@@ -1119,8 +1163,9 @@ static int check_owner(int type, int id)
        return 0;
 }
 
-int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
+int quotactl_ioctl(struct super_block *sb, struct if_quotactl *qctl)
 {
+       struct ll_sb_info *sbi = ll_s2sbi(sb);
        int cmd = qctl->qc_cmd;
        int type = qctl->qc_type;
        int id = qctl->qc_id;
@@ -1138,6 +1183,9 @@ int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
        case LUSTRE_Q_SETDEFAULT_POOL:
                if (!capable(CAP_SYS_ADMIN))
                        RETURN(-EPERM);
+
+               if (sb->s_flags & SB_RDONLY)
+                       RETURN(-EROFS);
                break;
        case Q_GETQUOTA:
        case LUSTRE_Q_GETDEFAULT:
@@ -1267,6 +1315,7 @@ out:
 int ll_rmfid(struct file *file, void __user *arg)
 {
        const struct fid_array __user *ufa = arg;
+       struct inode *inode = file_inode(file);
        struct fid_array *lfa = NULL;
        size_t size;
        unsigned nr;
@@ -1274,7 +1323,7 @@ int ll_rmfid(struct file *file, void __user *arg)
        ENTRY;
 
        if (!capable(CAP_DAC_READ_SEARCH) &&
-           !(ll_i2sbi(file_inode(file))->ll_flags & LL_SBI_USER_FID2PATH))
+           !test_bit(LL_SBI_USER_FID2PATH, ll_i2sbi(inode)->ll_flags))
                RETURN(-EPERM);
        /* Only need to get the buflen */
        if (get_user(nr, &ufa->fa_nr))
@@ -1718,6 +1767,7 @@ out_rmdir:
                __u32 __user *lmmsizep = NULL;
                struct lu_fid __user *fidp = NULL;
                int lmmsize;
+               bool api32;
 
                if (cmd == IOC_MDC_GETFILEINFO_V1 ||
                    cmd == IOC_MDC_GETFILEINFO_V2 ||
@@ -1785,6 +1835,7 @@ out_rmdir:
                                GOTO(out_req, rc = -EFAULT);
                        rc = -EOVERFLOW;
                }
+               api32 = test_bit(LL_SBI_32BIT_API, sbi->ll_flags);
 
                if (cmd == IOC_MDC_GETFILEINFO_V1 ||
                    cmd == LL_IOC_MDC_GETINFO_V1) {
@@ -1796,15 +1847,18 @@ out_rmdir:
                        st.st_uid       = body->mbo_uid;
                        st.st_gid       = body->mbo_gid;
                        st.st_rdev      = body->mbo_rdev;
-                       st.st_size      = body->mbo_size;
+                       if (llcrypt_require_key(inode) == -ENOKEY)
+                               st.st_size = round_up(st.st_size,
+                                                  LUSTRE_ENCRYPTION_UNIT_SIZE);
+                       else
+                               st.st_size = body->mbo_size;
                        st.st_blksize   = PAGE_SIZE;
                        st.st_blocks    = body->mbo_blocks;
                        st.st_atime     = body->mbo_atime;
                        st.st_mtime     = body->mbo_mtime;
                        st.st_ctime     = body->mbo_ctime;
                        st.st_ino       = cl_fid_build_ino(&body->mbo_fid1,
-                                               sbi->ll_flags &
-                                               LL_SBI_32BIT_API);
+                                                          api32);
 
                        if (copy_to_user(statp, &st, sizeof(st)))
                                GOTO(out_req, rc = -EFAULT);
@@ -1819,9 +1873,12 @@ out_rmdir:
                        stx.stx_gid = body->mbo_gid;
                        stx.stx_mode = body->mbo_mode;
                        stx.stx_ino = cl_fid_build_ino(&body->mbo_fid1,
-                                                      sbi->ll_flags &
-                                                      LL_SBI_32BIT_API);
-                       stx.stx_size = body->mbo_size;
+                                                      api32);
+                       if (llcrypt_require_key(inode) == -ENOKEY)
+                               stx.stx_size = round_up(stx.stx_size,
+                                                  LUSTRE_ENCRYPTION_UNIT_SIZE);
+                       else
+                               stx.stx_size = body->mbo_size;
                        stx.stx_blocks = body->mbo_blocks;
                        stx.stx_atime.tv_sec = body->mbo_atime;
                        stx.stx_ctime.tv_sec = body->mbo_ctime;
@@ -1895,7 +1952,7 @@ out_req:
                                GOTO(out_quotactl, rc = -EFAULT);
                }
 
-               rc = quotactl_ioctl(sbi, qctl);
+               rc = quotactl_ioctl(inode->i_sb, qctl);
                if (rc == 0 &&
                    copy_to_user((void __user *)arg, qctl, sizeof(*qctl)))
                         rc = -EFAULT;
@@ -2095,6 +2152,7 @@ out_hur:
                int len;
                char *filename;
                int namelen = 0;
+               __u32 flags;
                int rc;
 
                rc = obd_ioctl_getdata(&data, &len, (void __user *)arg);
@@ -2107,6 +2165,7 @@ out_hur:
 
                filename = data->ioc_inlbuf1;
                namelen = data->ioc_inllen1;
+               flags = data->ioc_type;
 
                if (namelen < 1 || namelen != strlen(filename) + 1) {
                        CDEBUG(D_INFO, "IOC_MDC_LOOKUP missing filename\n");
@@ -2122,7 +2181,7 @@ out_hur:
                        GOTO(migrate_free, rc);
                }
 
-               rc = ll_migrate(inode, file, lum, filename);
+               rc = ll_migrate(inode, file, lum, filename, flags);
 migrate_free:
                OBD_FREE_LARGE(data, len);
 
@@ -2132,6 +2191,8 @@ migrate_free:
                RETURN(ll_ioctl_fsgetxattr(inode, cmd, arg));
        case FS_IOC_FSSETXATTR:
                RETURN(ll_ioctl_fssetxattr(inode, cmd, arg));
+       case LL_IOC_PROJECT:
+               RETURN(ll_ioctl_project(file, cmd, arg));
        case LL_IOC_PCC_DETACH_BY_FID: {
                struct lu_pcc_detach_fid *detach;
                struct lu_fid *fid;
@@ -2234,10 +2295,13 @@ static loff_t ll_dir_seek(struct file *file, loff_t offset, int origin)
            ((api32 && offset <= LL_DIR_END_OFF_32BIT) ||
             (!api32 && offset <= LL_DIR_END_OFF))) {
                if (offset != file->f_pos) {
+                       bool hash64;
+
+                       hash64 = test_bit(LL_SBI_64BIT_HASH, sbi->ll_flags);
                        if ((api32 && offset == LL_DIR_END_OFF_32BIT) ||
                            (!api32 && offset == LL_DIR_END_OFF))
                                fd->lfd_pos = MDS_DIR_END_OFF;
-                       else if (api32 && sbi->ll_flags & LL_SBI_64BIT_HASH)
+                       else if (api32 && hash64)
                                fd->lfd_pos = offset << 32;
                        else
                                fd->lfd_pos = offset;