Whamcloud - gitweb
LU-12780 scrub: all update to bitfields must be protected.
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_scrub.c
index f6d7e4a..90f273e 100644 (file)
@@ -208,7 +208,7 @@ osd_scrub_convert_ff(struct osd_thread_info *info, struct osd_device *dev,
        if (rc == sizeof(*ff)) {
                /* 2) delete the old XATTR_NAME_FID */
                dquot_initialize(inode);
-               rc = osd_removexattr(dentry, inode, XATTR_NAME_FID);
+               rc = ll_vfs_removexattr(dentry, inode, XATTR_NAME_FID);
                if (rc)
                        GOTO(stop, rc);
 
@@ -339,8 +339,11 @@ iget:
                                GOTO(out, rc = 0);
                }
 
-               if (!scrub->os_partial_scan)
+               if (!scrub->os_partial_scan) {
+                       spin_lock(&scrub->os_lock);
                        scrub->os_full_speed = 1;
+                       spin_unlock(&scrub->os_lock);
+               }
 
                switch (val) {
                case SCRUB_NEXT_NOLMA:
@@ -367,9 +370,11 @@ iget:
 
                GOTO(out, rc = 0);
        } else {
-               if (!scrub->os_partial_scan)
+               if (!scrub->os_partial_scan) {
+                       spin_lock(&scrub->os_lock);
                        scrub->os_full_speed = 1;
-
+                       spin_unlock(&scrub->os_lock);
+               }
                sf->sf_flags |= SF_INCONSISTENT;
 
                /* XXX: If the device is restored from file-level backup, then
@@ -474,6 +479,7 @@ static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
        if (flags & SS_RESET)
                scrub_file_reset(scrub, dev->od_uuid, 0);
 
+       spin_lock(&scrub->os_lock);
        if (flags & SS_AUTO_FULL) {
                scrub->os_full_speed = 1;
                scrub->os_partial_scan = 0;
@@ -491,7 +497,6 @@ static int osd_scrub_prep(const struct lu_env *env, struct osd_device *dev)
                scrub->os_partial_scan = 0;
        }
 
-       spin_lock(&scrub->os_lock);
        scrub->os_in_prior = 0;
        scrub->os_waiting = 0;
        scrub->os_paused = 0;
@@ -783,16 +788,12 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev,
        struct osd_inode_id *lid;
        int rc;
 
-       if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_DELAY) && cfs_fail_val > 0) {
-               struct l_wait_info lwi;
-
-               lwi = LWI_TIMEOUT(cfs_time_seconds(cfs_fail_val), NULL, NULL);
-               if (likely(lwi.lwi_timeout > 0))
-                       l_wait_event(thread->t_ctl_waitq,
-                               !list_empty(&scrub->os_inconsistent_items) ||
-                               !thread_is_running(thread),
-                               &lwi);
-       }
+       if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_DELAY) && cfs_fail_val > 0)
+               wait_event_idle_timeout(
+                       thread->t_ctl_waitq,
+                       !list_empty(&scrub->os_inconsistent_items) ||
+                       !thread_is_running(thread),
+                       cfs_time_seconds(cfs_fail_val));
 
        if (OBD_FAIL_CHECK(OBD_FAIL_OSD_SCRUB_CRASH)) {
                spin_lock(&scrub->os_lock);
@@ -814,10 +815,10 @@ static int osd_scrub_next(struct osd_thread_info *info, struct osd_device *dev,
 
                        oii = list_entry(scrub->os_inconsistent_items.next,
                                struct osd_inconsistent_item, oii_list);
-                       spin_unlock(&scrub->os_lock);
 
                        *oic = &oii->oii_cache;
                        scrub->os_in_prior = 1;
+                       spin_unlock(&scrub->os_lock);
 
                        return 0;
                }
@@ -901,7 +902,9 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev,
 
        rc = osd_scrub_check_update(info, dev, oic, rc);
        if (rc != 0) {
+               spin_lock(&scrub->os_lock);
                scrub->os_in_prior = 0;
+               spin_unlock(&scrub->os_lock);
                return rc;
        }
 
@@ -914,7 +917,9 @@ static int osd_scrub_exec(struct osd_thread_info *info, struct osd_device *dev,
        }
 
        if (scrub->os_in_prior) {
+               spin_lock(&scrub->os_lock);
                scrub->os_in_prior = 0;
+               spin_unlock(&scrub->os_lock);
                return 0;
        }
 
@@ -975,6 +980,7 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
        LASSERT(!(flags & SS_AUTO_PARTIAL));
 
        down_write(&scrub->os_rwsem);
+       spin_lock(&scrub->os_lock);
        scrub->os_in_join = 1;
        if (flags & SS_SET_FAILOUT)
                sf->sf_param |= SP_FAILOUT;
@@ -1001,6 +1007,7 @@ static void osd_scrub_join(const struct lu_env *env, struct osd_device *dev,
                sf->sf_flags |= SF_AUTO;
                scrub->os_full_speed = 1;
        }
+       spin_unlock(&scrub->os_lock);
 
        scrub->os_new_checked = 0;
        if (sf->sf_pos_last_checkpoint != 0)
@@ -1083,7 +1090,7 @@ static int osd_inode_iteration(struct osd_thread_info *info,
                        if (rc == 0) {
                                __u64 used = ksfs->f_files - ksfs->f_ffree;
 
-                               do_div(used, sf->sf_items_updated_prior);
+                               used = div64_u64(used, sf->sf_items_updated_prior);
                                /* If we hit too much inconsistent OI
                                 * mappings during the partial scan,
                                 * then scan the device completely. */
@@ -1728,10 +1735,8 @@ struct osd_ios_item {
 };
 
 struct osd_ios_filldir_buf {
-#ifdef HAVE_DIR_CONTEXT
        /* please keep it as first member */
        struct dir_context       ctx;
-#endif
        struct osd_thread_info  *oifb_info;
        struct osd_device       *oifb_dev;
        struct dentry           *oifb_dentry;
@@ -1956,7 +1961,8 @@ osd_ios_scan_one(struct osd_thread_info *info, struct osd_device *dev,
                                               inode);
        }
 
-       rc = osd_oi_lookup(info, dev, &tfid, id2, 0);
+       /* Since this called from iterate_dir() the inode lock will be taken */
+       rc = osd_oi_lookup(info, dev, &tfid, id2, OI_LOCKED);
        if (rc != 0) {
                if (rc != -ENOENT)
                        RETURN(rc);
@@ -2019,16 +2025,17 @@ static int osd_ios_lf_fill(void *buf,
                RETURN(0);
 
        scrub->os_lf_scanned++;
-       child = osd_lookup_one_len_unlocked(dev, name, parent, namelen);
+       child = osd_lookup_one_len(dev, name, parent, namelen);
        if (IS_ERR(child)) {
+               rc = PTR_ERR(child);
                CDEBUG(D_LFSCK, "%s: cannot lookup child '%.*s': rc = %d\n",
-                     osd_name(dev), namelen, name, (int)PTR_ERR(child));
-               RETURN(0);
+                     osd_name(dev), namelen, name, rc);
+               RETURN(rc);
        } else if (!child->d_inode) {
                dput(child);
                CDEBUG(D_INODE, "%s: child '%.*s' lacks inode\n",
                       osd_name(dev), namelen, name);
-               RETURN(0);
+               RETURN(-ENOENT);
        }
 
        inode = child->d_inode;
@@ -2093,8 +2100,7 @@ static int osd_ios_varfid_fill(void *buf,
        if (name[0] == '.')
                RETURN(0);
 
-       child = osd_lookup_one_len_unlocked(dev, name, fill_buf->oifb_dentry,
-                                           namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
 
@@ -2142,8 +2148,7 @@ static int osd_ios_dl_fill(void *buf,
        if (map->olm_name == NULL)
                RETURN(0);
 
-       child = osd_lookup_one_len_unlocked(dev, name, fill_buf->oifb_dentry,
-                                           namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
 
@@ -2177,8 +2182,7 @@ static int osd_ios_uld_fill(void *buf,
        if (name[0] != '[')
                RETURN(0);
 
-       child = osd_lookup_one_len_unlocked(dev, name, fill_buf->oifb_dentry,
-                                           namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
 
@@ -2228,8 +2232,7 @@ static int osd_ios_root_fill(void *buf,
        if (map->olm_name == NULL)
                RETURN(0);
 
-       child = osd_lookup_one_len_unlocked(dev, name, fill_buf->oifb_dentry,
-                                           namelen);
+       child = osd_lookup_one_len(dev, name, fill_buf->oifb_dentry, namelen);
        if (IS_ERR(child))
                RETURN(PTR_ERR(child));
        else if (!child->d_inode)
@@ -2253,9 +2256,7 @@ osd_ios_general_scan(struct osd_thread_info *info, struct osd_device *dev,
                     struct dentry *dentry, filldir_t filldir)
 {
        struct osd_ios_filldir_buf    buf   = {
-#ifdef HAVE_DIR_CONTEXT
                                                .ctx.actor = filldir,
-#endif
                                                .oifb_info = info,
                                                .oifb_dev = dev,
                                                .oifb_dentry = dentry };
@@ -2269,21 +2270,20 @@ osd_ios_general_scan(struct osd_thread_info *info, struct osd_device *dev,
 
        filp->f_pos = 0;
        filp->f_path.dentry = dentry;
-       filp->f_mode = FMODE_64BITHASH;
+       filp->f_flags |= O_NOATIME;
+       filp->f_mode = FMODE_64BITHASH | FMODE_NONOTIFY;
        filp->f_mapping = inode->i_mapping;
        filp->f_op = fops;
        filp->private_data = NULL;
-       set_file_inode(filp, inode);
+       filp->f_cred = current_cred();
+       filp->f_inode = inode;
+       rc = osd_security_file_alloc(filp);
+       if (rc)
+               RETURN(rc);
 
        do {
                buf.oifb_items = 0;
-#ifdef HAVE_DIR_CONTEXT
-               buf.ctx.pos = filp->f_pos;
-               rc = fops->iterate_shared(filp, &buf.ctx);
-               filp->f_pos = buf.ctx.pos;
-#else
-               rc = fops->readdir(filp, &buf, filldir);
-#endif
+               rc = iterate_dir(filp, &buf.ctx);
        } while (rc >= 0 && buf.oifb_items > 0 &&
                 filp->f_pos != LDISKFS_HTREE_EOF_64BIT);
        fops->release(inode, filp);
@@ -2313,8 +2313,11 @@ osd_ios_ROOT_scan(struct osd_thread_info *info, struct osd_device *dev,
         *      FID directly, instead, the OI scrub will scan the OI structure
         *      and try to re-generate the LMA from the OI mapping. But if the
         *      OI mapping crashed or lost also, then we have to give up under
-        *      double failure cases. */
+        *      double failure cases.
+        */
+       spin_lock(&scrub->os_lock);
        scrub->os_convert_igif = 1;
+       spin_unlock(&scrub->os_lock);
        child = osd_lookup_one_len_unlocked(dev, dot_lustre_name, dentry,
                                            strlen(dot_lustre_name));
        if (IS_ERR(child)) {
@@ -2347,10 +2350,12 @@ osd_ios_ROOT_scan(struct osd_thread_info *info, struct osd_device *dev,
         * to access the ".lustre" with cached IGIF. So we prefer
         * to the solution 2).
         */
+       inode_lock(dentry->d_inode);
        rc = osd_ios_scan_one(info, dev, dentry->d_inode,
                              child->d_inode, &LU_DOT_LUSTRE_FID,
                              dot_lustre_name,
                              strlen(dot_lustre_name), 0);
+       inode_unlock(dentry->d_inode);
        if (rc == -ENOENT) {
 out_scrub:
                /* It is 1.8 MDT device. */
@@ -2393,9 +2398,11 @@ osd_ios_OBJECTS_scan(struct osd_thread_info *info, struct osd_device *dev,
        if (IS_ERR(child)) {
                rc = PTR_ERR(child);
        } else {
+               inode_lock(dentry->d_inode);
                rc = osd_ios_scan_one(info, dev, dentry->d_inode,
                                      child->d_inode, NULL, ADMIN_USR,
                                      strlen(ADMIN_USR), 0);
+               inode_unlock(dentry->d_inode);
                dput(child);
        }
 
@@ -2407,9 +2414,11 @@ osd_ios_OBJECTS_scan(struct osd_thread_info *info, struct osd_device *dev,
        if (IS_ERR(child))
                GOTO(out, rc = PTR_ERR(child));
 
+       inode_lock(dentry->d_inode);
        rc = osd_ios_scan_one(info, dev, dentry->d_inode,
                              child->d_inode, NULL, ADMIN_GRP,
                              strlen(ADMIN_GRP), 0);
+       inode_unlock(dentry->d_inode);
        dput(child);
 out:
        RETURN(rc == -ENOENT ? 0 : rc);
@@ -2429,6 +2438,12 @@ static void osd_initial_OI_scrub(struct osd_thread_info *info,
        dev->od_igif_inoi = 1;
 
        while (1) {
+               /* Don't take inode_lock here since scandir() callbacks
+                * can call VFS functions which may manully take the
+                * inode lock itself like iterate_dir(). Since this
+                * is the case it is best to leave the scandir()
+                * callbacks to managing the inode lock.
+                */
                scandir(info, dev, dentry, filldir);
                if (item != NULL) {
                        dput(item->oii_dentry);
@@ -2552,7 +2567,9 @@ void osd_scrub_stop(struct osd_device *dev)
 
        /* od_otable_mutex: prevent curcurrent start/stop */
        mutex_lock(&dev->od_otable_mutex);
+       spin_lock(&scrub->os_lock);
        scrub->os_paused = 1;
+       spin_unlock(&scrub->os_lock);
        scrub_stop(scrub);
        mutex_unlock(&dev->od_otable_mutex);
 }
@@ -2600,6 +2617,7 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
        }
 
        inode = file_inode(filp);
+       ldiskfs_set_inode_flag(inode, LDISKFS_INODE_JOURNAL_DATA);
        if (!dev->od_dt_dev.dd_rdonly) {
                /* 'What the @fid is' is not imporatant, because the object
                 * has no OI mapping, and only is visible inside the OSD.*/
@@ -2622,7 +2640,7 @@ int osd_scrub_setup(const struct lu_env *env, struct osd_device *dev)
                RETURN(obj ? PTR_ERR(obj) : -ENOENT);
 
 #ifndef HAVE_S_UUID_AS_UUID_T
-       memcpy(dev->od_uuid.b, sb->s_uuid, UUID_SIZE);
+       memcpy(dev->od_uuid.b, sb->s_uuid, sizeof(dev->od_uuid));
 #else
        uuid_copy(&dev->od_uuid, &sb->s_uuid);
 #endif
@@ -2751,8 +2769,6 @@ void osd_scrub_cleanup(const struct lu_env *env, struct osd_device *dev)
                dt_object_put_nocache(env, scrub->os_obj);
                scrub->os_obj = NULL;
        }
-       if (dev->od_oi_table != NULL)
-               osd_oi_fini(osd_oti_get(env), dev);
 }
 
 /* object table based iteration APIs */
@@ -3046,6 +3062,7 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic,
        oii->oii_cache = *oic;
        oii->oii_insert = insert;
 
+       spin_lock(&lscrub->os_lock);
        if (lscrub->os_partial_scan) {
                __u64 now = ktime_get_real_seconds();
 
@@ -3066,7 +3083,6 @@ int osd_oii_insert(struct osd_device *dev, struct osd_idmap_cache *oic,
                        lscrub->os_full_scrub = 1;
        }
 
-       spin_lock(&lscrub->os_lock);
        if (unlikely(!thread_is_running(thread))) {
                spin_unlock(&lscrub->os_lock);
                OBD_FREE_PTR(oii);