Whamcloud - gitweb
LU-4603 lmv: a few fixes about readdir of striped dir.
[fs/lustre-release.git] / lustre / llite / dir.c
index 2b1d227..22c4a42 100644 (file)
@@ -51,8 +51,8 @@
 #include <lustre/lustre_idl.h>
 #include <obd_support.h>
 #include <obd_class.h>
+#include <lustre_ioctl.h>
 #include <lustre_lib.h>
-#include <lustre/lustre_idl.h>
 #include <lustre_lite.h>
 #include <lustre_dlm.h>
 #include <lustre_fid.h>
@@ -162,16 +162,18 @@ struct lu_dirent *ll_dir_entry_start(struct inode *dir,
                                     struct md_op_data *op_data,
                                     struct page **ppage)
 {
-       struct lu_dirent *entry;
+       struct lu_dirent *entry = NULL;
        struct md_callback cb_op;
        int rc;
+       ENTRY;
 
        LASSERT(*ppage == NULL);
        cb_op.md_blocking_ast = ll_md_blocking_ast;
+       op_data->op_cli_flags &= ~CLI_NEXT_ENTRY;
        rc = md_read_entry(ll_i2mdexp(dir), op_data, &cb_op, &entry, ppage);
        if (rc != 0)
                entry = ERR_PTR(rc);
-       return entry;
+       RETURN(entry);
 }
 
 struct lu_dirent *ll_dir_entry_next(struct inode *dir,
@@ -179,25 +181,36 @@ struct lu_dirent *ll_dir_entry_next(struct inode *dir,
                                    struct lu_dirent *ent,
                                    struct page **ppage)
 {
-       struct lu_dirent *entry;
+       struct lu_dirent *entry = NULL;
        struct md_callback cb_op;
        int rc;
+       ENTRY;
 
-       LASSERT(*ppage != NULL);
-       cb_op.md_blocking_ast = ll_md_blocking_ast;
        op_data->op_hash_offset = le64_to_cpu(ent->lde_hash);
+
+       /* release last page */
+       LASSERT(*ppage != NULL);
        kunmap(*ppage);
        page_cache_release(*ppage);
-       *ppage = NULL;
+
+       cb_op.md_blocking_ast = ll_md_blocking_ast;
+       op_data->op_cli_flags |= CLI_NEXT_ENTRY;
        rc = md_read_entry(ll_i2mdexp(dir), op_data, &cb_op, &entry, ppage);
        if (rc != 0)
                entry = ERR_PTR(rc);
-       return entry;
+
+       RETURN(entry);
 }
 
+#ifdef HAVE_DIR_CONTEXT
+int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
+               struct dir_context *ctx)
+{
+#else
 int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
                void *cookie, filldir_t filldir)
 {
+#endif
        struct ll_sb_info       *sbi = ll_i2sbi(inode);
        struct ll_dir_chain     chain;
        struct lu_dirent        *ent;
@@ -206,7 +219,6 @@ int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
        int                     done = 0;
        int                     rc = 0;
        __u64                   hash = MDS_DIR_END_OFF;
-       __u64                   last_hash = MDS_DIR_END_OFF;
        struct page             *page = NULL;
        ENTRY;
 
@@ -241,23 +253,28 @@ int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
                fid_le_to_cpu(&fid, &ent->lde_fid);
                ino = cl_fid_build_ino(&fid, api32);
                type = ll_dirent_type_get(ent);
+
+#ifdef HAVE_DIR_CONTEXT
                /* For 'll_nfs_get_name_filldir()', it will try
                 * to access the 'ent' through its 'lde_name',
                 * so the parameter 'name' for 'filldir()' must
                 * be part of the 'ent'. */
+               done = !dir_emit(ctx, ent->lde_name, namelen, ino, type);
+#else
                done = filldir(cookie, ent->lde_name, namelen, lhash,
                               ino, type);
+#endif
                if (done) {
                        if (op_data->op_hash_offset != MDS_DIR_END_OFF)
-                               op_data->op_hash_offset = last_hash;
+                               op_data->op_hash_offset = hash;
                        break;
-               } else {
-                       last_hash = hash;
                }
        }
 
        if (IS_ERR(ent))
                rc = PTR_ERR(ent);
+       else if (ent == NULL)
+               op_data->op_hash_offset = MDS_DIR_END_OFF;
 
        if (page != NULL) {
                kunmap(page);
@@ -268,7 +285,11 @@ int ll_dir_read(struct inode *inode, struct md_op_data *op_data,
        RETURN(rc);
 }
 
+#ifdef HAVE_DIR_CONTEXT
+static int ll_iterate(struct file *filp, struct dir_context *ctx)
+#else
 static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
+#endif
 {
        struct inode            *inode  = filp->f_dentry->d_inode;
        struct ll_file_data     *lfd    = LUSTRE_FPRIVATE(filp);
@@ -278,9 +299,6 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
        struct md_op_data       *op_data;
        __u64                   pos;
        int                     rc;
-#ifdef HAVE_TOUCH_ATIME_1ARG
-       struct path             path;
-#endif
        ENTRY;
 
        if (lfd != NULL)
@@ -303,37 +321,57 @@ static int ll_readdir(struct file *filp, void *cookie, filldir_t filldir)
        if (IS_ERR(op_data))
                GOTO(out, rc = PTR_ERR(op_data));
 
+       if (unlikely(op_data->op_mea1 != NULL)) {
+               /* This is only needed for striped dir to fill ..,
+                * see lmv_read_entry */
+               if (filp->f_dentry->d_parent != NULL &&
+                   filp->f_dentry->d_parent->d_inode != NULL) {
+                       __u64 ibits = MDS_INODELOCK_UPDATE;
+                       struct inode *parent =
+                               filp->f_dentry->d_parent->d_inode;
+
+                       if (ll_have_md_lock(parent, &ibits, LCK_MINMODE))
+                               op_data->op_fid3 = *ll_inode2fid(parent);
+               }
+
+               /* If it can not find in cache, do lookup .. on the master
+                * object */
+               if (fid_is_zero(&op_data->op_fid3)) {
+                       rc = ll_dir_get_parent_fid(inode, &op_data->op_fid3);
+                       if (rc != 0)
+                               RETURN(rc);
+               }
+       }
        op_data->op_hash_offset = pos;
-       op_data->op_max_pages = sbi->ll_md_brw_size >> PAGE_CACHE_SHIFT;
+       op_data->op_max_pages = sbi->ll_md_brw_pages;
+#ifdef HAVE_DIR_CONTEXT
+       ctx->pos = pos;
+       rc = ll_dir_read(inode, op_data, ctx);
+       pos = ctx->pos;
+#else
        rc = ll_dir_read(inode, op_data, cookie, filldir);
+#endif
        if (lfd != NULL)
                lfd->lfd_pos = op_data->op_hash_offset;
 
        if (pos == MDS_DIR_END_OFF) {
                if (api32)
-                       filp->f_pos = LL_DIR_END_OFF_32BIT;
+                       pos = LL_DIR_END_OFF_32BIT;
                else
-                       filp->f_pos = LL_DIR_END_OFF;
+                       pos = LL_DIR_END_OFF;
        } else {
                if (api32 && hash64)
-                       filp->f_pos = op_data->op_hash_offset >> 32;
+                       pos = op_data->op_hash_offset >> 32;
                else
-                       filp->f_pos = op_data->op_hash_offset;
+                       pos = op_data->op_hash_offset;
        }
-
-       ll_finish_md_op_data(op_data);
-       filp->f_version = inode->i_version;
-#ifdef HAVE_TOUCH_ATIME_1ARG
-#ifdef HAVE_F_PATH_MNT
-       path.mnt = filp->f_path.mnt;
+#ifdef HAVE_DIR_CONTEXT
+       ctx->pos = pos;
 #else
-       path.mnt = filp->f_vfsmnt;
-#endif
-       path.dentry = filp->f_dentry;
-       touch_atime(&path);
-#else
-       touch_atime(filp->f_vfsmnt, filp->f_dentry);
+       filp->f_pos = pos;
 #endif
+       ll_finish_md_op_data(op_data);
+       filp->f_version = inode->i_version;
 
 out:
        if (!rc)
@@ -342,7 +380,7 @@ out:
        RETURN(rc);
 }
 
-int ll_send_mgc_param(struct obd_export *mgc, char *string)
+static int ll_send_mgc_param(struct obd_export *mgc, char *string)
 {
         struct mgs_send_param *msp;
         int rc = 0;
@@ -374,16 +412,6 @@ static int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
        if (unlikely(lump->lum_magic != LMV_USER_MAGIC))
                RETURN(-EINVAL);
 
-       if (lump->lum_stripe_offset == (__u32)-1) {
-               int mdtidx;
-
-               mdtidx = ll_get_mdt_idx(dir);
-               if (mdtidx < 0)
-                       RETURN(mdtidx);
-
-               lump->lum_stripe_offset = mdtidx;
-       }
-
        CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p) name %s"
               "stripe_offset %d, stripe_count: %u\n",
               PFID(ll_inode2fid(dir)), dir, filename,
@@ -401,7 +429,8 @@ static int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
 
        op_data->op_cli_flags |= CLI_SET_MEA;
        err = md_create(sbi->ll_md_exp, op_data, lump, sizeof(*lump), mode,
-                       current_fsuid(), current_fsgid(),
+                       from_kuid(&init_user_ns, current_fsuid()),
+                       from_kgid(&init_user_ns, current_fsgid()),
                        cfs_curproc_cap_pack(), 0, &request);
        ll_finish_md_op_data(op_data);
        if (err)
@@ -540,7 +569,7 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
        struct md_op_data *op_data;
        ENTRY;
 
-       rc = ll_get_max_mdsize(sbi, &lmm_size);
+       rc = ll_get_default_mdsize(sbi, &lmm_size);
        if (rc)
                RETURN(rc);
 
@@ -588,8 +617,8 @@ int ll_dir_getstripe(struct inode *inode, void **plmm, int *plmm_size,
                if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC))
                        lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)lmm);
                break;
-       case LMV_MAGIC:
-               if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC))
+       case LMV_MAGIC_V1:
+               if (LMV_MAGIC != cpu_to_le32(LMV_MAGIC))
                        lustre_swab_lmv_mds_md((union lmv_mds_md *)lmm);
                break;
        case LMV_USER_MAGIC:
@@ -607,8 +636,7 @@ out:
        return rc;
 }
 
-static int ll_get_mdt_idx_by_fid(struct ll_sb_info *sbi,
-                                const struct lu_fid *fid)
+int ll_get_mdt_idx_by_fid(struct ll_sb_info *sbi, const struct lu_fid *fid)
 {
        struct md_op_data       *op_data;
        int                     rc;
@@ -853,8 +881,10 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl)
                         RETURN(-EPERM);
                 break;
        case Q_GETQUOTA:
-               if (((type == USRQUOTA && current_euid() != id) ||
-                    (type == GRPQUOTA && !in_egroup_p(id))) &&
+               if (((type == USRQUOTA &&
+                     !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) ||
+                    (type == GRPQUOTA &&
+                     !in_egroup_p(make_kgid(&init_user_ns, id)))) &&
                    (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
                     sbi->ll_flags & LL_SBI_RMT_CLIENT))
                        RETURN(-EPERM);
@@ -1034,39 +1064,29 @@ static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                 return 0;
         }
         case IOC_MDC_LOOKUP: {
-                struct ptlrpc_request *request = NULL;
-                int namelen, len = 0;
-                char *buf = NULL;
-                char *filename;
-                struct md_op_data *op_data;
+               int namelen, len = 0;
+               char *buf = NULL;
+               char *filename;
 
-                rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
-                if (rc)
-                        RETURN(rc);
-                data = (void *)buf;
-
-                filename = data->ioc_inlbuf1;
-                namelen = strlen(filename);
-
-                if (namelen < 1) {
-                        CDEBUG(D_INFO, "IOC_MDC_LOOKUP missing filename\n");
-                        GOTO(out_free, rc = -EINVAL);
-                }
+               rc = obd_ioctl_getdata(&buf, &len, (void *)arg);
+               if (rc != 0)
+                       RETURN(rc);
+               data = (void *)buf;
 
-                op_data = ll_prep_md_op_data(NULL, inode, NULL, filename, namelen,
-                                             0, LUSTRE_OPC_ANY, NULL);
-                if (IS_ERR(op_data))
-                        GOTO(out_free, rc = PTR_ERR(op_data));
+               filename = data->ioc_inlbuf1;
+               namelen = strlen(filename);
+               if (namelen < 1) {
+                       CDEBUG(D_INFO, "IOC_MDC_LOOKUP missing filename\n");
+                       GOTO(out_free, rc = -EINVAL);
+               }
 
-                op_data->op_valid = OBD_MD_FLID;
-                rc = md_getattr_name(sbi->ll_md_exp, op_data, &request);
-                ll_finish_md_op_data(op_data);
-                if (rc < 0) {
-                        CDEBUG(D_INFO, "md_getattr_name: %d\n", rc);
-                        GOTO(out_free, rc);
-                }
-                ptlrpc_req_finished(request);
-                EXIT;
+               rc = ll_get_fid_by_name(inode, filename, namelen, NULL);
+               if (rc < 0) {
+                       CERROR("%s: lookup %.*s failed: rc = %d\n",
+                              ll_get_fsname(inode->i_sb, NULL, 0), namelen,
+                              filename, rc);
+                       GOTO(out_free, rc);
+               }
 out_free:
                 obd_ioctl_freedata(buf, len);
                 return rc;
@@ -1190,7 +1210,7 @@ lmv_out_free:
 
                rc = ll_dir_getstripe(inode, (void **)&lmm, &lmmsize, &request,
                                      valid);
-               if (rc != 0 && rc != -ENODATA)
+               if (rc != 0)
                        GOTO(finish_req, rc);
 
                /* Get default LMV EA */
@@ -1207,38 +1227,29 @@ lmv_out_free:
                        GOTO(finish_req, rc);
                }
 
-               /* Get normal LMV EA */
-               if (rc == -ENODATA) {
-                       stripe_count = 1;
-               } else {
-                       LASSERT(lmm != NULL);
-                       stripe_count = lmv_mds_md_stripe_count_get(lmm);
-               }
-
+               stripe_count = lmv_mds_md_stripe_count_get(lmm);
                lum_size = lmv_user_md_size(stripe_count, LMV_MAGIC_V1);
                OBD_ALLOC(tmp, lum_size);
                if (tmp == NULL)
                        GOTO(finish_req, rc = -ENOMEM);
 
-               tmp->lum_magic = LMV_MAGIC_V1;
-               tmp->lum_stripe_count = 1;
                mdt_index = ll_get_mdt_idx(inode);
                if (mdt_index < 0)
                        GOTO(out_tmp, rc = -ENOMEM);
+
+               tmp->lum_magic = LMV_MAGIC_V1;
+               tmp->lum_stripe_count = 0;
                tmp->lum_stripe_offset = mdt_index;
-               tmp->lum_objects[0].lum_mds = mdt_index;
-               tmp->lum_objects[0].lum_fid = *ll_inode2fid(inode);
-               for (i = 1; i < stripe_count; i++) {
-                       struct lmv_mds_md_v1 *lmm1;
-
-                       lmm1 = &lmm->lmv_md_v1;
-                       mdt_index = ll_get_mdt_idx_by_fid(sbi,
-                                                    &lmm1->lmv_stripe_fids[i]);
+               for (i = 0; i < stripe_count; i++) {
+                       struct lu_fid   *fid;
+
+                       fid = &lmm->lmv_md_v1.lmv_stripe_fids[i];
+                       mdt_index = ll_get_mdt_idx_by_fid(sbi, fid);
                        if (mdt_index < 0)
                                GOTO(out_tmp, rc = mdt_index);
 
                        tmp->lum_objects[i].lum_mds = mdt_index;
-                       tmp->lum_objects[i].lum_fid = lmm1->lmv_stripe_fids[i];
+                       tmp->lum_objects[i].lum_fid = *fid;
                        tmp->lum_stripe_count++;
                }
 
@@ -1280,8 +1291,8 @@ out_rmdir:
        }
        case LL_IOC_LOV_SWAP_LAYOUTS:
                RETURN(-EPERM);
-        case LL_IOC_OBD_STATFS:
-                RETURN(ll_obd_statfs(inode, (void *)arg));
+       case IOC_OBD_STATFS:
+               RETURN(ll_obd_statfs(inode, (void *)arg));
         case LL_IOC_LOV_GETSTRIPE:
         case LL_IOC_MDC_GETINFO:
         case IOC_MDC_GETFILEINFO:
@@ -1432,10 +1443,7 @@ out_rmdir:
                 OBD_FREE_LARGE(lmm, lmmsize);
                 return rc;
         }
-        case OBD_IOC_LLOG_CATINFO: {
-               RETURN(-EOPNOTSUPP);
-        }
-        case OBD_IOC_QUOTACHECK: {
+       case OBD_IOC_QUOTACHECK: {
                 struct obd_quotactl *oqctl;
                 int error = 0;
 
@@ -1460,7 +1468,7 @@ out_rmdir:
                 OBD_FREE_PTR(oqctl);
                 return error ?: rc;
         }
-        case OBD_IOC_POLL_QUOTACHECK: {
+       case OBD_IOC_POLL_QUOTACHECK: {
                 struct if_quotacheck *check;
 
                 if (!cfs_capable(CFS_CAP_SYS_ADMIN) ||
@@ -1548,7 +1556,7 @@ out_rmdir:
 #else
 #warning "remove old LL_IOC_QUOTACTL_18 compatibility code"
 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 50, 0) */
-        case LL_IOC_QUOTACTL: {
+       case OBD_IOC_QUOTACTL: {
                 struct if_quotactl *qctl;
 
                 OBD_ALLOC_PTR(qctl);
@@ -1642,8 +1650,8 @@ out_rmdir:
                totalsize = hur_len(hur);
                OBD_FREE_PTR(hur);
 
-               /* Make sure the size is reasonable */
-               if (totalsize >= MDS_MAXREQSIZE)
+               /* Final size will be more than double totalsize */
+               if (totalsize >= MDS_MAXREQSIZE / 3)
                        RETURN(-E2BIG);
 
                OBD_ALLOC_LARGE(hur, totalsize);
@@ -1749,6 +1757,39 @@ out_rmdir:
                OBD_FREE_PTR(copy);
                RETURN(rc);
        }
+       case LL_IOC_MIGRATE: {
+               char            *buf = NULL;
+               const char      *filename;
+               int             namelen = 0;
+               int             len;
+               int             rc;
+               int             mdtidx;
+
+               rc = obd_ioctl_getdata(&buf, &len, (void __user *)arg);
+               if (rc < 0)
+                       RETURN(rc);
+
+               data = (struct obd_ioctl_data *)buf;
+               if (data->ioc_inlbuf1 == NULL || data->ioc_inlbuf2 == NULL ||
+                   data->ioc_inllen1 == 0 || data->ioc_inllen2 == 0)
+                       GOTO(migrate_free, rc = -EINVAL);
+
+               filename = data->ioc_inlbuf1;
+               namelen = data->ioc_inllen1;
+               /* \0 is packed at the end of filename */
+               if (namelen < 1 || namelen != strlen(filename) + 1)
+                       GOTO(migrate_free, rc = -EINVAL);
+
+               if (data->ioc_inllen2 != sizeof(mdtidx))
+                       GOTO(migrate_free, rc = -EINVAL);
+               mdtidx = *(int *)data->ioc_inlbuf2;
+
+               rc = ll_migrate(inode, file, mdtidx, filename, namelen - 1);
+migrate_free:
+               obd_ioctl_freedata(buf, len);
+
+               RETURN(rc);
+       }
        default:
                RETURN(obd_iocontrol(cmd, sbi->ll_dt_exp, 0, NULL,
                                     (void *)arg));
@@ -1806,24 +1847,28 @@ out:
         return ret;
 }
 
-int ll_dir_open(struct inode *inode, struct file *file)
+static int ll_dir_open(struct inode *inode, struct file *file)
 {
         ENTRY;
         RETURN(ll_file_open(inode, file));
 }
 
-int ll_dir_release(struct inode *inode, struct file *file)
+static int ll_dir_release(struct inode *inode, struct file *file)
 {
         ENTRY;
         RETURN(ll_file_release(inode, file));
 }
 
-struct file_operations ll_dir_operations = {
-        .llseek   = ll_dir_seek,
-        .open     = ll_dir_open,
-        .release  = ll_dir_release,
-        .read     = generic_read_dir,
-        .readdir  = ll_readdir,
-        .unlocked_ioctl   = ll_dir_ioctl,
-        .fsync    = ll_fsync,
+const struct file_operations ll_dir_operations = {
+       .llseek         = ll_dir_seek,
+       .open           = ll_dir_open,
+       .release        = ll_dir_release,
+       .read           = generic_read_dir,
+#ifdef HAVE_DIR_CONTEXT
+       .iterate        = ll_iterate,
+#else
+       .readdir        = ll_readdir,
+#endif
+       .unlocked_ioctl = ll_dir_ioctl,
+       .fsync          = ll_fsync,
 };