static int osd_remove_ois(struct osd_thread_info *info, struct osd_device *osd) { char name[16]; int namelen; int rc; int i; for (i = 0; i < osd->od_scrub.os_file.sf_oi_count; i++) { namelen = snprintf(name, sizeof(name), "%s.%d", OSD_OI_NAME_BASE, i); rc = osd_remove_oi_one(osd_sb(osd)->s_root, name, namelen); if (rc != 0) { CERROR("%.16s: fail to remove the stale OI file %s: " "rc = %d\n", LDISKFS_SB(osd_sb(osd))->s_es->s_volume_name, name, rc); return rc; } } namelen = snprintf(name, sizeof(name), "%s", OSD_OI_NAME_BASE); rc = osd_remove_oi_one(osd_sb(osd)->s_root, name, namelen); if (rc != 0) CERROR("%.16s: fail to remove the stale OI file %s: rc = %d\n", LDISKFS_SB(osd_sb(osd))->s_es->s_volume_name, name, rc); return rc; }
int osd_oi_lookup(struct osd_thread_info *info, struct osd_device *osd, const struct lu_fid *fid, struct osd_inode_id *id, enum oi_check_flags flags) { if (unlikely(fid_is_last_id(fid))) return osd_obj_spec_lookup(info, osd, fid, id); if (fid_is_on_ost(info, osd, fid, flags) || fid_is_llog(fid)) return osd_obj_map_lookup(info, osd, fid, id); if (unlikely(fid_seq(fid) == FID_SEQ_LOCAL_FILE)) { int rc; if (fid_is_fs_root(fid)) { osd_id_gen(id, osd_sb(osd)->s_root->d_inode->i_ino, osd_sb(osd)->s_root->d_inode->i_generation); return 0; } if (unlikely(fid_is_acct(fid))) return osd_acct_obj_lookup(info, osd, fid, id); /* For other special FIDs, try OI first, then do spec lookup */ rc = __osd_oi_lookup(info, osd, fid, id); if (rc == -ENOENT) return osd_obj_spec_lookup(info, osd, fid, id); return rc; } if (!osd->od_igif_inoi && fid_is_igif(fid)) { osd_id_gen(id, lu_igif_ino(fid), lu_igif_gen(fid)); return 0; } return __osd_oi_lookup(info, osd, fid, id); }
int osd_oi_lookup(struct osd_thread_info *info, struct osd_device *osd, const struct lu_fid *fid, struct osd_inode_id *id, enum oi_check_flags flags) { if (unlikely(fid_is_last_id(fid))) return osd_obj_spec_lookup(info, osd, fid, id); if (fid_is_on_ost(info, osd, fid, flags) || fid_is_llog(fid)) return osd_obj_map_lookup(info, osd, fid, id); if (fid_is_fs_root(fid)) { osd_id_gen(id, osd_sb(osd)->s_root->d_inode->i_ino, osd_sb(osd)->s_root->d_inode->i_generation); return 0; } if (unlikely(fid_is_acct(fid))) return osd_acct_obj_lookup(info, osd, fid, id); if (!osd->od_igif_inoi && fid_is_igif(fid)) { osd_id_gen(id, lu_igif_ino(fid), lu_igif_gen(fid)); return 0; } return __osd_oi_lookup(info, osd, fid, id); }
/** * Open OI(Object Index) table. * If \a oi_count is zero, which means caller doesn't know how many OIs there * will be, this function can either return 0 for new filesystem, or number * of OIs on existed filesystem. * * If \a oi_count is non-zero, which means caller does know number of OIs on * filesystem, this function should return the exactly same number on * success, or error code in failure. * * \param oi_count Number of expected OI containers * \param create Create OIs if doesn't exist * * \retval +ve number of opened OI containers * \retval 0 no OI containers found * \retval -ve failure */ static int osd_oi_table_open(struct osd_thread_info *info, struct osd_device *osd, struct osd_oi **oi_table, unsigned oi_count, bool create) { struct scrub_file *sf = &osd->od_scrub.os_file; int count = 0; int rc = 0; int i; ENTRY; /* NB: oi_count != 0 means that we have already created/known all OIs * and have known exact number of OIs. */ LASSERT(oi_count <= OSD_OI_FID_NR_MAX); for (i = 0; i < (oi_count != 0 ? oi_count : OSD_OI_FID_NR_MAX); i++) { char name[12]; if (oi_table[i] != NULL) { count++; continue; } sprintf(name, "%s.%d", OSD_OI_NAME_BASE, i); rc = osd_oi_open(info, osd, name, &oi_table[i], create); if (rc == 0) { count++; continue; } if (rc == -ENOENT && create == false) { if (oi_count == 0) return count; rc = 0; ldiskfs_set_bit(i, sf->sf_oi_bitmap); continue; } CERROR("%.16s: can't open %s: rc = %d\n", LDISKFS_SB(osd_sb(osd))->s_es->s_volume_name, name, rc); if (oi_count > 0) CERROR("%.16s: expect to open total %d OI files.\n", LDISKFS_SB(osd_sb(osd))->s_es->s_volume_name, oi_count); break; } if (rc < 0) { osd_oi_table_put(info, oi_table, oi_count > 0 ? oi_count : i); count = rc; } RETURN(count); }
int osd_compat_spec_lookup(struct osd_thread_info *info, struct osd_device *osd, const struct lu_fid *fid, struct osd_inode_id *id) { struct dentry *dentry; char *name; int rc = -ERESTART; ENTRY; name = oid2name(fid_oid(fid)); if (name == NULL || strlen(name) == 0) return -ERESTART; dentry = ll_lookup_one_len(name, osd_sb(osd)->s_root, strlen(name)); if (!IS_ERR(dentry)) { if (dentry->d_inode) { if (is_bad_inode(dentry->d_inode)) { rc = -EIO; } else { id->oii_ino = dentry->d_inode->i_ino; id->oii_gen = dentry->d_inode->i_generation; rc = 0; } } dput(dentry); } RETURN(rc); }
int osd_compat_spec_insert(struct osd_thread_info *info, struct osd_device *osd, const struct lu_fid *fid, const struct osd_inode_id *id, struct thandle *th) { struct osd_compat_objid *map = osd->od_ost_map; struct dentry *root = osd_sb(osd)->s_root; char *name; int rc = 0; int seq; ENTRY; if (fid_oid(fid) >= OFD_GROUP0_LAST_OID && fid_oid(fid) < OFD_GROUP4K_LAST_OID) { /* on creation of LAST_ID we create O/<group> hierarchy */ LASSERT(map); seq = fid_oid(fid) - OFD_GROUP0_LAST_OID; LASSERT(seq < MAX_OBJID_GROUP); LASSERT(map->groups[seq].groot); } else { name = oid2name(fid_oid(fid)); if (name == NULL) CWARN("UNKNOWN COMPAT FID "DFID"\n", PFID(fid)); else if (name[0]) rc = osd_compat_add_entry(info, osd, root, name, id, th); } RETURN(rc); }
int osd_compat_add_entry(struct osd_thread_info *info, struct osd_device *osd, struct dentry *dir, char *name, const struct osd_inode_id *id, struct thandle *th) { struct osd_thandle *oh; struct dentry *child; struct inode *inode; int rc; ENTRY; oh = container_of(th, struct osd_thandle, ot_super); LASSERT(oh->ot_handle != NULL); LASSERT(oh->ot_handle->h_transaction != NULL); inode = &info->oti_inode; inode->i_sb = osd_sb(osd); inode->i_ino = id->oii_ino; inode->i_generation = id->oii_gen; child = &info->oti_child_dentry; child->d_name.hash = 0; child->d_name.name = name; child->d_name.len = strlen(name); child->d_parent = dir; child->d_inode = inode; LOCK_INODE_MUTEX(dir->d_inode); rc = osd_ldiskfs_add_entry(oh->ot_handle, child, inode, NULL); UNLOCK_INODE_MUTEX(dir->d_inode); RETURN(rc); }
void osd_brw_stats_update(struct osd_device *osd, struct osd_iobuf *iobuf) { struct brw_stats *s = &osd->od_brw_stats; unsigned long *last_block = NULL; struct page **pages = iobuf->dr_pages; struct page *last_page = NULL; unsigned long discont_pages = 0; unsigned long discont_blocks = 0; unsigned long *blocks = iobuf->dr_blocks; int i, nr_pages = iobuf->dr_npages; int blocks_per_page; int rw = iobuf->dr_rw; if (unlikely(nr_pages == 0)) return; blocks_per_page = PAGE_CACHE_SIZE >> osd_sb(osd)->s_blocksize_bits; lprocfs_oh_tally_log2(&s->hist[BRW_R_PAGES+rw], nr_pages); while (nr_pages-- > 0) { if (last_page && (*pages)->index != (last_page->index + 1)) discont_pages++; last_page = *pages; pages++; for (i = 0; i < blocks_per_page; i++) { if (last_block && *blocks != (*last_block + 1)) discont_blocks++; last_block = blocks++; } } lprocfs_oh_tally(&s->hist[BRW_R_DISCONT_PAGES+rw], discont_pages); lprocfs_oh_tally(&s->hist[BRW_R_DISCONT_BLOCKS+rw], discont_blocks); }
static struct inode *osd_oi_index_open(struct osd_thread_info *info, struct osd_device *osd, const char *name, struct dt_index_features *f, bool create) { struct dentry *dentry; struct inode *inode; int rc; dentry = ll_lookup_one_len(name, osd_sb(osd)->s_root, strlen(name)); if (IS_ERR(dentry)) return (void *) dentry; if (dentry->d_inode) { LASSERT(!is_bad_inode(dentry->d_inode)); inode = dentry->d_inode; atomic_inc(&inode->i_count); dput(dentry); return inode; } /* create */ dput(dentry); shrink_dcache_parent(osd_sb(osd)->s_root); if (!create) return ERR_PTR(-ENOENT); rc = osd_oi_index_create_one(info, osd, name, f); if (rc) return ERR_PTR(rc); dentry = ll_lookup_one_len(name, osd_sb(osd)->s_root, strlen(name)); if (IS_ERR(dentry)) return (void *) dentry; if (dentry->d_inode) { LASSERT(!is_bad_inode(dentry->d_inode)); inode = dentry->d_inode; atomic_inc(&inode->i_count); dput(dentry); return inode; } return ERR_PTR(-ENOENT); }
static int osd_oi_index_create_one(struct osd_thread_info *info, struct osd_device *osd, const char *name, struct dt_index_features *feat) { const struct lu_env *env = info->oti_env; struct osd_inode_id *id = &info->oti_id; struct buffer_head *bh; struct inode *inode; struct ldiskfs_dir_entry_2 *de; struct dentry *dentry; struct super_block *sb = osd_sb(osd); struct inode *dir = sb->s_root->d_inode; handle_t *jh; int rc; dentry = osd_child_dentry_by_inode(env, dir, name, strlen(name)); bh = osd_ldiskfs_find_entry(dir, &dentry->d_name, &de, NULL, NULL); if (bh) { osd_id_gen(id, le32_to_cpu(de->inode), OSD_OII_NOGEN); brelse(bh); inode = osd_iget(info, osd, id); if (!IS_ERR(inode)) { iput(inode); inode = ERR_PTR(-EEXIST); } return PTR_ERR(inode); } jh = osd_journal_start_sb(sb, LDISKFS_HT_MISC, 100); if (IS_ERR(jh)) return PTR_ERR(jh); inode = ldiskfs_create_inode(jh, dir, (S_IFREG | S_IRUGO | S_IWUSR)); if (IS_ERR(inode)) { ldiskfs_journal_stop(jh); return PTR_ERR(inode); } ldiskfs_set_inode_state(inode, LDISKFS_STATE_LUSTRE_NOSCRUB); unlock_new_inode(inode); if (feat->dif_flags & DT_IND_VARKEY) rc = iam_lvar_create(inode, feat->dif_keysize_max, feat->dif_ptrsize, feat->dif_recsize_max, jh); else rc = iam_lfix_create(inode, feat->dif_keysize_max, feat->dif_ptrsize, feat->dif_recsize_max, jh); dentry = osd_child_dentry_by_inode(env, dir, name, strlen(name)); rc = osd_ldiskfs_add_entry(info, jh, dentry, inode, NULL); ldiskfs_journal_stop(jh); iput(inode); return rc; }
/* * directory structure on legacy OST: * * O/<seq>/d0-31/<objid> * O/<seq>/LAST_ID * last_rcvd * LAST_GROUP * CONFIGS * */ int osd_compat_init(struct osd_device *dev) { struct lvfs_run_ctxt new; struct lvfs_run_ctxt save; struct dentry *rootd = osd_sb(dev)->s_root; struct dentry *d; int rc; int i; ENTRY; /* to get subdir count from last_rcvd */ rc = osd_last_rcvd_subdir_count(dev); if (rc <= 0) RETURN(rc); dev->od_ost_map->subdir_count = rc; rc = 0; OBD_ALLOC_PTR(dev->od_ost_map); if (dev->od_ost_map == NULL) RETURN(-ENOMEM); LASSERT(dev->od_fsops); osd_push_ctxt(dev, &new, &save); d = simple_mkdir(rootd, dev->od_mnt, "O", 0755, 1); pop_ctxt(&save, &new, NULL); if (IS_ERR(d)) { OBD_FREE_PTR(dev->od_ost_map); RETURN(PTR_ERR(d)); } dev->od_ost_map->root = d; /* Initialize all groups */ for (i = 0; i < MAX_OBJID_GROUP; i++) { cfs_sema_init(&dev->od_ost_map->groups[i].dir_init_sem, 1); rc = osd_compat_seq_init(dev, i); if (rc) { osd_compat_fini(dev); break; } } RETURN(rc); }
int osd_last_rcvd_subdir_count(struct osd_device *osd) { struct lr_server_data lsd; struct dentry *dlast; loff_t off; int rc = 0; int count = 0; ENTRY; dlast = ll_lookup_one_len(LAST_RCVD, osd_sb(osd)->s_root, strlen(LAST_RCVD)); if (IS_ERR(dlast)) return PTR_ERR(dlast); else if (dlast->d_inode == NULL) goto out; off = 0; rc = osd_ldiskfs_read(dlast->d_inode, &lsd, sizeof(lsd), &off); if (rc == sizeof(lsd)) { CDEBUG(D_INFO, "read last_rcvd header, uuid = %s, " "subdir count = %d\n", lsd.lsd_uuid, lsd.lsd_subdir_count); count = le16_to_cpu(lsd.lsd_subdir_count); } else if (rc != 0) { CERROR("Can't read last_rcvd file, rc = %d\n", rc); if (rc > 0) rc = -EFAULT; goto out; } else { count = FILTER_SUBDIR_COUNT; } rc = count; out: dput(dlast); return rc; }
int osd_oi_insert(struct osd_thread_info *info, struct osd_device *osd, const struct lu_fid *fid, const struct osd_inode_id *id, handle_t *th, enum oi_check_flags flags) { struct lu_fid *oi_fid = &info->oti_fid2; struct osd_inode_id *oi_id = &info->oti_id2; int rc = 0; if (unlikely(fid_is_last_id(fid))) return osd_obj_spec_insert(info, osd, fid, id, th); if (fid_is_on_ost(info, osd, fid, flags) || fid_is_llog(fid)) return osd_obj_map_insert(info, osd, fid, id, th); fid_cpu_to_be(oi_fid, fid); osd_id_pack(oi_id, id); rc = osd_oi_iam_refresh(info, osd_fid2oi(osd, fid), (const struct dt_rec *)oi_id, (const struct dt_key *)oi_fid, th, true); if (rc != 0) { struct inode *inode; struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs; if (rc != -EEXIST) return rc; rc = osd_oi_lookup(info, osd, fid, oi_id, 0); if (rc != 0) return rc; if (unlikely(osd_id_eq(id, oi_id))) return 1; /* Check whether the mapping for oi_id is valid or not. */ inode = osd_iget(info, osd, oi_id); if (IS_ERR(inode)) { rc = PTR_ERR(inode); if (rc == -ENOENT || rc == -ESTALE) goto update; return rc; } /* The EA inode should NOT be in OI, old OI scrub may added * such OI mapping by wrong, replace it. */ if (unlikely(osd_is_ea_inode(inode))) { iput(inode); goto update; } rc = osd_get_lma(info, inode, &info->oti_obj_dentry, lma); iput(inode); if (rc == -ENODATA) goto update; if (rc != 0) return rc; if (!(lma->lma_compat & LMAC_NOT_IN_OI) && lu_fid_eq(fid, &lma->lma_self_fid)) { CERROR("%.16s: the FID "DFID" is used by two objects: " "%u/%u %u/%u\n", LDISKFS_SB(osd_sb(osd))->s_es->s_volume_name, PFID(fid), oi_id->oii_ino, oi_id->oii_gen, id->oii_ino, id->oii_gen); return -EEXIST; } update: osd_id_pack(oi_id, id); rc = osd_oi_iam_refresh(info, osd_fid2oi(osd, fid), (const struct dt_rec *)oi_id, (const struct dt_key *)oi_fid, th, false); if (rc != 0) return rc; } if (unlikely(fid_seq(fid) == FID_SEQ_LOCAL_FILE)) rc = osd_obj_spec_insert(info, osd, fid, id, th); return rc; }
int osd_oi_init(struct osd_thread_info *info, struct osd_device *osd, bool restored) { struct osd_scrub *scrub = &osd->od_scrub; struct scrub_file *sf = &scrub->os_file; struct osd_oi **oi; int rc; ENTRY; if (restored) { rc = osd_remove_ois(info, osd); if (rc != 0) return rc; } OBD_ALLOC(oi, sizeof(*oi) * OSD_OI_FID_NR_MAX); if (oi == NULL) RETURN(-ENOMEM); mutex_lock(&oi_init_lock); /* try to open existing multiple OIs first */ rc = osd_oi_table_open(info, osd, oi, sf->sf_oi_count, false); if (rc < 0) GOTO(out, rc); if (rc > 0) { if (rc == sf->sf_oi_count || sf->sf_oi_count == 0) GOTO(out, rc); osd_scrub_file_reset(scrub, LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, SF_RECREATED); osd_oi_count = sf->sf_oi_count; goto create; } /* if previous failed then try found single OI from old filesystem */ rc = osd_oi_open(info, osd, OSD_OI_NAME_BASE, &oi[0], false); if (rc == 0) { /* found single OI from old filesystem */ ldiskfs_clear_bit(0, sf->sf_oi_bitmap); if (sf->sf_success_count == 0) /* XXX: There is one corner case that if the OI_scrub * file crashed or lost and we regard it upgrade, * then we allow IGIF lookup to bypass OI files. * * The risk is that osd_fid_lookup() may found * a wrong inode with the given IGIF especially * when the MDT has performed file-level backup * and restored after former upgrading from 1.8 * to 2.x. Fortunately, the osd_fid_lookup()can * verify the inode to decrease the risk. */ osd_scrub_file_reset(scrub, LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, SF_UPGRADE); GOTO(out, rc = 1); } else if (rc != -ENOENT) { CERROR("%.16s: can't open %s: rc = %d\n", LDISKFS_SB(osd_sb(osd))->s_es->s_volume_name, OSD_OI_NAME_BASE, rc); GOTO(out, rc); } if (sf->sf_oi_count > 0) { int i; memset(sf->sf_oi_bitmap, 0, SCRUB_OI_BITMAP_SIZE); for (i = 0; i < osd_oi_count; i++) ldiskfs_set_bit(i, sf->sf_oi_bitmap); osd_scrub_file_reset(scrub, LDISKFS_SB(osd_sb(osd))->s_es->s_uuid, SF_RECREATED); } sf->sf_oi_count = osd_oi_count; create: rc = osd_scrub_file_store(scrub); if (rc < 0) { osd_oi_table_put(info, oi, sf->sf_oi_count); GOTO(out, rc); } /* No OIs exist, new filesystem, create OI objects */ rc = osd_oi_table_open(info, osd, oi, osd_oi_count, true); LASSERT(ergo(rc >= 0, rc == osd_oi_count)); GOTO(out, rc); out: if (rc < 0) { OBD_FREE(oi, sizeof(*oi) * OSD_OI_FID_NR_MAX); } else { LASSERT((rc & (rc - 1)) == 0); osd->od_oi_table = oi; osd->od_oi_count = rc; if (sf->sf_oi_count != rc) { sf->sf_oi_count = rc; rc = osd_scrub_file_store(scrub); if (rc < 0) { osd_oi_table_put(info, oi, sf->sf_oi_count); OBD_FREE(oi, sizeof(*oi) * OSD_OI_FID_NR_MAX); } } else { rc = 0; } } mutex_unlock(&oi_init_lock); return rc; }