X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;ds=sidebyside;f=lustre%2Fosd-ldiskfs%2Fosd_handler.c;h=db890c785c64b1f3adbfa06593f1768aebbab7f9;hb=80ad9c5cb2419899ed4bab8a5d6eb7fa58729073;hp=6db8e25c897af6d99ca2b34b8f71b2bbbffb65d0;hpb=fafa0e31a54281167eebd615da847866eaf03a93;p=fs%2Flustre-release.git diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 6db8e25..db890c7 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -72,6 +72,8 @@ /* llo_* api support */ #include +/* dt_acct_features */ +#include #ifdef HAVE_LDISKFS_PDO int ldiskfs_pdo = 1; @@ -88,6 +90,7 @@ static const char remote_obj_dir[] = "REM_OBJ_DIR"; static const struct lu_object_operations osd_lu_obj_ops; static const struct dt_object_operations osd_obj_ops; static const struct dt_object_operations osd_obj_ea_ops; +static const struct dt_object_operations osd_obj_otable_it_ops; static const struct dt_index_operations osd_index_iam_ops; static const struct dt_index_operations osd_index_ea_ops; @@ -103,11 +106,17 @@ static int osd_object_invariant(const struct lu_object *l) #ifdef HAVE_QUOTA_SUPPORT static inline void -osd_push_ctxt(const struct lu_env *env, struct osd_ctxt *save) +osd_push_ctxt(const struct lu_env *env, struct osd_ctxt *save, bool is_md) { - struct md_ucred *uc = md_ucred(env); + struct md_ucred *uc; struct cred *tc; + if (!is_md) + /* OFD support */ + return; + + uc = md_ucred(env); + LASSERT(uc != NULL); save->oc_uid = current_fsuid(); @@ -123,10 +132,14 @@ osd_push_ctxt(const struct lu_env *env, struct osd_ctxt *save) } static inline void -osd_pop_ctxt(struct osd_ctxt *save) +osd_pop_ctxt(struct osd_ctxt *save, bool is_md) { struct cred *tc; + if (!is_md) + /* OFD support */ + return; + if ((tc = prepare_creds())) { tc->fsuid = save->oc_uid; tc->fsgid = save->oc_gid; @@ -298,8 +311,8 @@ struct inode *osd_iget(struct osd_thread_info *info, struct osd_device *dev, iput(inode); inode = ERR_PTR(-ESTALE); } else if (is_bad_inode(inode)) { - CWARN("%s: bad inode: ino = %u\n", - dev->od_dt_dev.dd_lu_dev.ld_obd->obd_name, id->oii_ino); + CWARN("%.16s: bad inode: ino = %u\n", + LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name, id->oii_ino); iput(inode); inode = ERR_PTR(-ENOENT); } else { @@ -340,53 +353,136 @@ struct inode *osd_iget_fid(struct osd_thread_info *info, struct osd_device *dev, return inode; } -static int osd_fid_lookup(const struct lu_env *env, - struct osd_object *obj, const struct lu_fid *fid) +static struct inode * +osd_iget_verify(struct osd_thread_info *info, struct osd_device *dev, + struct osd_inode_id *id, const struct lu_fid *fid) { - struct osd_thread_info *info; - struct lu_device *ldev = obj->oo_dt.do_lu.lo_dev; - struct osd_device *dev; - struct osd_inode_id *id; - struct inode *inode; - int result; + struct lustre_mdt_attrs *lma = &info->oti_mdt_attrs; + struct inode *inode; + int rc; - LINVRNT(osd_invariant(obj)); - LASSERT(obj->oo_inode == NULL); - LASSERTF(fid_is_sane(fid) || fid_is_idif(fid), DFID, PFID(fid)); - /* - * This assertion checks that osd layer sees only local - * fids. Unfortunately it is somewhat expensive (does a - * cache-lookup). Disabling it for production/acceptance-testing. - */ - LASSERT(1 || fid_is_local(env, ldev->ld_site, fid)); + inode = osd_iget(info, dev, id); + if (IS_ERR(inode)) + return inode; - ENTRY; + rc = osd_get_lma(inode, &info->oti_obj_dentry, lma); + if (rc != 0) { + if (rc == -ENODATA) { + CDEBUG(D_LFSCK, "inconsistent obj: NULL, %lu, "DFID"\n", + inode->i_ino, PFID(fid)); + rc = -EREMCHG; + } + iput(inode); + return ERR_PTR(rc); + } - info = osd_oti_get(env); - LASSERT(info); - dev = osd_dev(ldev); - id = &info->oti_id; + if (!lu_fid_eq(fid, &lma->lma_self_fid)) { + CDEBUG(D_LFSCK, "inconsistent obj: "DFID", %lu, "DFID"\n", + PFID(&lma->lma_self_fid), inode->i_ino, PFID(fid)); + iput(inode); + return ERR_PTR(EREMCHG); + } + return inode; +} - if (OBD_FAIL_CHECK(OBD_FAIL_OST_ENOENT)) - RETURN(-ENOENT); +static int osd_fid_lookup(const struct lu_env *env, struct osd_object *obj, + const struct lu_fid *fid, + const struct lu_object_conf *conf) +{ + struct osd_thread_info *info; + struct lu_device *ldev = obj->oo_dt.do_lu.lo_dev; + struct osd_device *dev; + struct osd_idmap_cache *oic; + struct osd_inode_id *id; + struct inode *inode; + struct osd_scrub *scrub; + struct scrub_file *sf; + int result; + int verify = 0; + ENTRY; - result = osd_oi_lookup(info, dev, fid, id); - if (result != 0) { - if (result == -ENOENT) - result = 0; - GOTO(out, result); - } + LINVRNT(osd_invariant(obj)); + LASSERT(obj->oo_inode == NULL); + LASSERTF(fid_is_sane(fid) || fid_is_idif(fid), DFID, PFID(fid)); + + dev = osd_dev(ldev); + scrub = &dev->od_scrub; + sf = &scrub->os_file; + info = osd_oti_get(env); + LASSERT(info); + oic = &info->oti_cache; + id = &oic->oic_lid; + + if (OBD_FAIL_CHECK(OBD_FAIL_OST_ENOENT)) + RETURN(-ENOENT); + + if (fid_is_norm(fid)) { + /* Search order: 1. per-thread cache. */ + if (lu_fid_eq(fid, &oic->oic_fid)) { + goto iget; + } else if (!cfs_list_empty(&scrub->os_inconsistent_items)) { + /* Search order: 2. OI scrub pending list. */ + result = osd_oii_lookup(dev, fid, id); + if (result == 0) + goto iget; + } + + if (sf->sf_flags & SF_INCONSISTENT) + verify = 1; + } + + /* + * Objects are created as locking anchors or place holders for objects + * yet to be created. No need to osd_oi_lookup() at here because FID + * shouldn't never be re-used, if it's really a duplicate FID from + * unexpected reason, we should be able to detect it later by calling + * do_create->osd_oi_insert() + */ + if (conf != NULL && (conf->loc_flags & LOC_F_NEW) != 0) + GOTO(out, result = 0); + + /* Search order: 3. OI files. */ + result = osd_oi_lookup(info, dev, fid, id); + if (result == -ENOENT) { + if (!fid_is_norm(fid) || + !ldiskfs_test_bit(osd_oi_fid2idx(dev,fid), + sf->sf_oi_bitmap)) + GOTO(out, result = 0); + + goto trigger; + } + + if (result != 0) + GOTO(out, result); + +iget: + if (verify == 0) + inode = osd_iget(info, dev, id); + else + inode = osd_iget_verify(info, dev, id, fid); + if (IS_ERR(inode)) { + result = PTR_ERR(inode); + if (result == -ENOENT || result == -ESTALE) { + fid_zero(&oic->oic_fid); + result = 0; + } else if (result == -EREMCHG) { + +trigger: + if (thread_is_running(&scrub->os_thread)) { + result = -EINPROGRESS; + } else if (!scrub->os_no_scrub) { + result = osd_scrub_start(dev); + LCONSOLE_ERROR("%.16s: trigger OI scrub by RPC " + "for "DFID", rc = %d [1]\n", + LDISKFS_SB(osd_sb(dev))->s_es->\ + s_volume_name,PFID(fid), result); + if (result == 0 || result == -EALREADY) + result = -EINPROGRESS; + else + result = -EREMCHG; + } + } - inode = osd_iget(info, dev, id); - if (IS_ERR(inode)) { - /* - * If fid wasn't found in oi, inode-less object is - * created, for which lu_object_exists() returns - * false. This is used in a (frequent) case when - * objects are created as locking anchors or - * place holders for objects yet to be created. - */ - result = PTR_ERR(inode); GOTO(out, result); } @@ -430,21 +526,26 @@ static void osd_object_init0(struct osd_object *obj) * life-cycle. */ static int osd_object_init(const struct lu_env *env, struct lu_object *l, - const struct lu_object_conf *unused) + const struct lu_object_conf *conf) { - struct osd_object *obj = osd_obj(l); - int result; + struct osd_object *obj = osd_obj(l); + int result; - LINVRNT(osd_invariant(obj)); + LINVRNT(osd_invariant(obj)); - result = osd_fid_lookup(env, obj, lu_object_fid(l)); - obj->oo_dt.do_body_ops = &osd_body_ops_new; - if (result == 0) { - if (obj->oo_inode != NULL) - osd_object_init0(obj); - } - LINVRNT(osd_invariant(obj)); - return result; + result = osd_fid_lookup(env, obj, lu_object_fid(l), conf); + obj->oo_dt.do_body_ops = &osd_body_ops_new; + if (result == 0) { + if (obj->oo_inode != NULL) { + osd_object_init0(obj); + } else if (fid_is_otable_it(&l->lo_header->loh_fid)) { + obj->oo_dt.do_ops = &osd_obj_otable_it_ops; + /* LFSCK iterator object is special without inode */ + l->lo_header->loh_attr |= LOHA_EXISTS; + } + } + LINVRNT(osd_invariant(obj)); + return result; } /* @@ -613,6 +714,9 @@ static void osd_trans_commit_cb(struct journal_callback *jcb, int error) /* call per-transaction callbacks if any */ cfs_list_for_each_entry_safe(dcb, tmp, &oh->ot_dcb_list, dcb_linkage) { + LASSERTF(dcb->dcb_magic == TRANS_COMMIT_CB_MAGIC, + "commit callback entry: magic=%x name='%s'\n", + dcb->dcb_magic, dcb->dcb_name); cfs_list_del_init(&dcb->dcb_linkage); dcb->dcb_func(NULL, th, dcb, error); } @@ -678,9 +782,10 @@ int osd_trans_start(const struct lu_env *env, struct dt_device *d, GOTO(out, rc); if (!osd_param_is_sane(dev, th)) { - CWARN("%s: too many transaction credits (%d > %d)\n", - d->dd_lu_dev.ld_obd->obd_name, oh->ot_credits, - osd_journal(dev)->j_max_transaction_buffers); + CWARN("%.16s: too many transaction credits (%d > %d)\n", + LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name, + oh->ot_credits, + osd_journal(dev)->j_max_transaction_buffers); /* XXX Limit the credits to 'max_transaction_buffers', and * let the underlying filesystem to catch the error if * we really need so many credits. @@ -727,7 +832,7 @@ int osd_trans_start(const struct lu_env *env, struct dt_device *d, * data (ofd) and reverse ordering for metadata * (mdd). then at some point we'll fix the latter */ - if (lu_device_is_md(&d->dd_lu_dev)) { + if (dev->od_is_md) { LASSERT(oti->oti_r_locks == 0); LASSERT(oti->oti_w_locks == 0); } @@ -780,7 +885,7 @@ static int osd_trans_stop(const struct lu_env *env, struct thandle *th) * data (ofd) and reverse ordering for metadata * (mdd). then at some point we'll fix the latter */ - if (lu_device_is_md(&th->th_dev->dd_lu_dev)) { + if (osd_dt_dev(th->th_dev)->od_is_md) { LASSERT(oti->oti_r_locks == 0); LASSERT(oti->oti_w_locks == 0); } @@ -815,12 +920,14 @@ static int osd_trans_stop(const struct lu_env *env, struct thandle *th) static int osd_trans_cb_add(struct thandle *th, struct dt_txn_commit_cb *dcb) { - struct osd_thandle *oh = container_of0(th, struct osd_thandle, - ot_super); + struct osd_thandle *oh = container_of0(th, struct osd_thandle, + ot_super); - cfs_list_add(&dcb->dcb_linkage, &oh->ot_dcb_list); + LASSERT(dcb->dcb_magic == TRANS_COMMIT_CB_MAGIC); + LASSERT(&dcb->dcb_func != NULL); + cfs_list_add(&dcb->dcb_linkage, &oh->ot_dcb_list); - return 0; + return 0; } /* @@ -887,6 +994,9 @@ int osd_statfs(const struct lu_env *env, struct dt_device *d, struct kstatfs *ksfs; int result = 0; + if (unlikely(osd->od_mount == NULL)) + return -EINPROGRESS; + /* osd_lproc.c call this without env, allocate ksfs for that case */ if (unlikely(env == NULL)) { OBD_ALLOC_PTR(ksfs); @@ -896,15 +1006,15 @@ int osd_statfs(const struct lu_env *env, struct dt_device *d, ksfs = &osd_oti_get(env)->oti_ksfs; } - cfs_spin_lock(&osd->od_osfs_lock); - /* cache 1 second */ - if (cfs_time_before_64(osd->od_osfs_age, cfs_time_shift_64(-1))) { - result = ll_do_statfs(sb, ksfs); - if (likely(result == 0)) { /* N.B. statfs can't really fail */ - osd->od_osfs_age = cfs_time_current_64(); - statfs_pack(&osd->od_statfs, ksfs); - } - } + cfs_spin_lock(&osd->od_osfs_lock); + /* cache 1 second */ + if (cfs_time_before_64(osd->od_osfs_age, cfs_time_shift_64(-1))) { + result = sb->s_op->statfs(sb->s_root, ksfs); + if (likely(result == 0)) { /* N.B. statfs can't really fail */ + osd->od_osfs_age = cfs_time_current_64(); + statfs_pack(&osd->od_statfs, ksfs); + } + } if (likely(result == 0)) *sfs = osd->od_statfs; @@ -1283,15 +1393,15 @@ int osd_object_auth(const struct lu_env *env, struct dt_object *dt, } static struct timespec *osd_inode_time(const struct lu_env *env, - struct inode *inode, __u64 seconds) + struct inode *inode, __u64 seconds) { - struct osd_thread_info *oti = osd_oti_get(env); - struct timespec *t = &oti->oti_time; + struct osd_thread_info *oti = osd_oti_get(env); + struct timespec *t = &oti->oti_time; - t->tv_sec = seconds; - t->tv_nsec = 0; - *t = timespec_trunc(*t, get_sb_time_gran(inode->i_sb)); - return t; + t->tv_sec = seconds; + t->tv_nsec = 0; + *t = timespec_trunc(*t, inode->i_sb->s_time_gran); + return t; } @@ -1313,8 +1423,8 @@ static void osd_inode_getattr(const struct lu_env *env, attr->la_flags = LDISKFS_I(inode)->i_flags; attr->la_nlink = inode->i_nlink; attr->la_rdev = inode->i_rdev; - attr->la_blksize = ll_inode_blksize(inode); - attr->la_blkbits = inode->i_blkbits; + attr->la_blksize = 1 << inode->i_blkbits; + attr->la_blkbits = inode->i_blkbits; } static int osd_attr_get(const struct lu_env *env, @@ -1418,6 +1528,32 @@ static int osd_inode_setattr(const struct lu_env *env, return 0; } +static int osd_quota_transfer(struct inode *inode, const struct lu_attr *attr) +{ + if ((attr->la_valid & LA_UID && attr->la_uid != inode->i_uid) || + (attr->la_valid & LA_GID && attr->la_gid != inode->i_gid)) { + struct iattr iattr; + int rc; + + iattr.ia_valid = 0; + if (attr->la_valid & LA_UID) + iattr.ia_valid |= ATTR_UID; + if (attr->la_valid & LA_GID) + iattr.ia_valid |= ATTR_GID; + iattr.ia_uid = attr->la_uid; + iattr.ia_gid = attr->la_gid; + + rc = ll_vfs_dq_transfer(inode, &iattr); + if (rc) { + CERROR("%s: quota transfer failed: rc = %d. Is quota " + "enforcement enabled on the ldiskfs filesystem?", + inode->i_sb->s_id, rc); + return rc; + } + } + return 0; +} + static int osd_attr_set(const struct lu_env *env, struct dt_object *dt, const struct lu_attr *attr, @@ -1438,28 +1574,34 @@ static int osd_attr_set(const struct lu_env *env, OSD_EXEC_OP(handle, attr_set); inode = obj->oo_inode; + if (!osd_dt_dev(handle->th_dev)->od_is_md) { + /* OFD support */ + rc = osd_quota_transfer(inode, attr); + if (rc) + return rc; + } else { #ifdef HAVE_QUOTA_SUPPORT - if ((attr->la_valid & LA_UID && attr->la_uid != inode->i_uid) || - (attr->la_valid & LA_GID && attr->la_gid != inode->i_gid)) { - struct osd_ctxt *save = &osd_oti_get(env)->oti_ctxt; - struct iattr iattr; - int rc; - - iattr.ia_valid = 0; - if (attr->la_valid & LA_UID) - iattr.ia_valid |= ATTR_UID; - if (attr->la_valid & LA_GID) - iattr.ia_valid |= ATTR_GID; - iattr.ia_uid = attr->la_uid; - iattr.ia_gid = attr->la_gid; - osd_push_ctxt(env, save); - rc = ll_vfs_dq_transfer(inode, &iattr) ? -EDQUOT : 0; - osd_pop_ctxt(save); - if (rc != 0) - return rc; - } + if ((attr->la_valid & LA_UID && attr->la_uid != inode->i_uid) || + (attr->la_valid & LA_GID && attr->la_gid != inode->i_gid)) { + struct osd_ctxt *save = &osd_oti_get(env)->oti_ctxt; + struct iattr iattr; + int rc; + + iattr.ia_valid = 0; + if (attr->la_valid & LA_UID) + iattr.ia_valid |= ATTR_UID; + if (attr->la_valid & LA_GID) + iattr.ia_valid |= ATTR_GID; + iattr.ia_uid = attr->la_uid; + iattr.ia_gid = attr->la_gid; + osd_push_ctxt(env, save, 1); + rc = ll_vfs_dq_transfer(inode, &iattr) ? -EDQUOT : 0; + osd_pop_ctxt(save, 1); + if (rc != 0) + return rc; + } #endif - + } cfs_spin_lock(&obj->oo_guard); rc = osd_inode_setattr(env, inode, attr); cfs_spin_unlock(&obj->oo_guard); @@ -1469,26 +1611,6 @@ static int osd_attr_set(const struct lu_env *env, return rc; } -/* - * Object creation. - * - * XXX temporary solution. - */ -static int osd_create_pre(struct osd_thread_info *info, struct osd_object *obj, - struct lu_attr *attr, struct thandle *th) -{ - return 0; -} - -static int osd_create_post(struct osd_thread_info *info, struct osd_object *obj, - struct lu_attr *attr, struct thandle *th) -{ - osd_object_init0(obj); - if (obj->oo_inode && (obj->oo_inode->i_state & I_NEW)) - unlock_new_inode(obj->oo_inode); - return 0; -} - struct dentry *osd_child_dentry_get(const struct lu_env *env, struct osd_object *obj, const char *name, const int namelen) @@ -1527,14 +1649,14 @@ static int osd_mkfile(struct osd_thread_info *info, struct osd_object *obj, parent = hint->dah_parent; #ifdef HAVE_QUOTA_SUPPORT - osd_push_ctxt(info->oti_env, save); + osd_push_ctxt(info->oti_env, save, osd_dt_dev(th->th_dev)->od_is_md); #endif inode = ldiskfs_create_inode(oth->ot_handle, parent ? osd_dt_obj(parent)->oo_inode : osd_sb(osd)->s_root->d_inode, mode); #ifdef HAVE_QUOTA_SUPPORT - osd_pop_ctxt(save); + osd_pop_ctxt(save, osd_dt_dev(th->th_dev)->od_is_md); #endif if (!IS_ERR(inode)) { /* Do not update file c/mtime in ldiskfs. @@ -1598,7 +1720,7 @@ static int osd_mk_index(struct osd_thread_info *info, struct osd_object *obj, struct osd_thandle *oth; const struct dt_index_features *feat = dof->u.dof_idx.di_feat; - __u32 mode = (attr->la_mode & (S_IFMT | S_IRWXUGO | S_ISVTX)); + __u32 mode = (attr->la_mode & (S_IFMT | S_IALLUGO | S_ISVTX)); LASSERT(S_ISREG(attr->la_mode)); @@ -1633,7 +1755,7 @@ static int osd_mkreg(struct osd_thread_info *info, struct osd_object *obj, { LASSERT(S_ISREG(attr->la_mode)); return osd_mkfile(info, obj, (attr->la_mode & - (S_IFMT | S_IRWXUGO | S_ISVTX)), hint, th); + (S_IFMT | S_IALLUGO | S_ISVTX)), hint, th); } static int osd_mksym(struct osd_thread_info *info, struct osd_object *obj, @@ -1644,7 +1766,7 @@ static int osd_mksym(struct osd_thread_info *info, struct osd_object *obj, { LASSERT(S_ISLNK(attr->la_mode)); return osd_mkfile(info, obj, (attr->la_mode & - (S_IFMT | S_IRWXUGO | S_ISVTX)), hint, th); + (S_IFMT | S_IALLUGO | S_ISVTX)), hint, th); } static int osd_mknod(struct osd_thread_info *info, struct osd_object *obj, @@ -1653,7 +1775,7 @@ static int osd_mknod(struct osd_thread_info *info, struct osd_object *obj, struct dt_object_format *dof, struct thandle *th) { - cfs_umode_t mode = attr->la_mode & (S_IFMT | S_IRWXUGO | S_ISVTX); + cfs_umode_t mode = attr->la_mode & (S_IFMT | S_IALLUGO | S_ISVTX); int result; LINVRNT(osd_invariant(obj)); @@ -1664,6 +1786,10 @@ static int osd_mknod(struct osd_thread_info *info, struct osd_object *obj, result = osd_mkfile(info, obj, mode, hint, th); if (result == 0) { LASSERT(obj->oo_inode != NULL); + /* + * This inode should be marked dirty for i_rdev. Currently + * that is done in the osd_attr_init(). + */ init_special_inode(obj->oo_inode, mode, attr->la_rdev); } LINVRNT(osd_invariant(obj)); @@ -1715,6 +1841,51 @@ static void osd_ah_init(const struct lu_env *env, struct dt_allocation_hint *ah, ah->dah_mode = child_mode; } +static void osd_attr_init(struct osd_thread_info *info, struct osd_object *obj, + struct lu_attr *attr, struct dt_object_format *dof) +{ + struct inode *inode = obj->oo_inode; + __u64 valid = attr->la_valid; + int result; + + attr->la_valid &= ~(LA_TYPE | LA_MODE); + + if (dof->dof_type != DFT_NODE) + attr->la_valid &= ~LA_RDEV; + if ((valid & LA_ATIME) && (attr->la_atime == LTIME_S(inode->i_atime))) + attr->la_valid &= ~LA_ATIME; + if ((valid & LA_CTIME) && (attr->la_ctime == LTIME_S(inode->i_ctime))) + attr->la_valid &= ~LA_CTIME; + if ((valid & LA_MTIME) && (attr->la_mtime == LTIME_S(inode->i_mtime))) + attr->la_valid &= ~LA_MTIME; + + if (!osd_obj2dev(obj)->od_is_md) { + /* OFD support */ + result = osd_quota_transfer(inode, attr); + if (result) + return; + } else { +#ifdef HAVE_QUOTA_SUPPORT + attr->la_valid &= ~(LA_UID | LA_GID); +#endif + } + + if (attr->la_valid != 0) { + result = osd_inode_setattr(info->oti_env, inode, attr); + /* + * The osd_inode_setattr() should always succeed here. The + * only error that could be returned is EDQUOT when we are + * trying to change the UID or GID of the inode. However, this + * should not happen since quota enforcement is no longer + * enabled on ldiskfs (lquota takes care of it). + */ + LASSERTF(result == 0, "%d", result); + inode->i_sb->s_op->dirty_inode(inode); + } + + attr->la_valid = valid; +} + /** * Helper function for osd_object_create() * @@ -1726,16 +1897,26 @@ static int __osd_object_create(struct osd_thread_info *info, struct dt_object_format *dof, struct thandle *th) { + int result; + __u32 umask; - int result; + /* we drop umask so that permissions we pass are not affected */ + umask = current->fs->umask; + current->fs->umask = 0; - result = osd_create_pre(info, obj, attr, th); + result = osd_create_type_f(dof->dof_type)(info, obj, attr, hint, dof, + th); if (result == 0) { - result = osd_create_type_f(dof->dof_type)(info, obj, - attr, hint, dof, th); - if (result == 0) - result = osd_create_post(info, obj, attr, th); + osd_attr_init(info, obj, attr, dof); + osd_object_init0(obj); + /* bz 24037 */ + if (obj->oo_inode && (obj->oo_inode->i_state & I_NEW)) + unlock_new_inode(obj->oo_inode); } + + /* restore previous umask value */ + current->fs->umask = umask; + return result; } @@ -1750,10 +1931,13 @@ static int __osd_oi_insert(const struct lu_env *env, struct osd_object *obj, struct osd_thread_info *info = osd_oti_get(env); struct osd_inode_id *id = &info->oti_id; struct osd_device *osd = osd_obj2dev(obj); - struct md_ucred *uc = md_ucred(env); LASSERT(obj->oo_inode != NULL); - LASSERT(uc != NULL); + + if (osd->od_is_md) { + struct md_ucred *uc = md_ucred(env); + LASSERT(uc != NULL); + } osd_id_gen(id, obj->oo_inode->i_ino, obj->oo_inode->i_generation); return osd_oi_insert(info, osd, fid, id, th); @@ -1817,6 +2001,11 @@ static int osd_object_create(const struct lu_env *env, struct dt_object *dt, LASSERT(osd_write_locked(env, obj)); LASSERT(th != NULL); + if (unlikely(fid_is_acct(fid))) + /* Quota files can't be created from the kernel any more, + * 'tune2fs -O quota' will take care of creating them */ + RETURN(-EPERM); + OSD_EXEC_OP(th, create); result = __osd_object_create(info, obj, attr, hint, dof, th); @@ -1875,6 +2064,9 @@ static int osd_object_destroy(const struct lu_env *env, LASSERT(inode); LASSERT(!lu_object_is_dying(dt->do_lu.lo_header)); + if (unlikely(fid_is_acct(fid))) + RETURN(-EPERM); + /* Parallel control for OI scrub. For most of cases, there is no * lock contention. So it will not affect unlink performance. */ cfs_mutex_lock(&inode->i_mutex); @@ -1982,11 +2174,11 @@ void osd_get_ldiskfs_dirent_param(struct ldiskfs_dentry_param *param, * \retval 0 on success */ static int osd_ea_fid_get(const struct lu_env *env, struct osd_object *obj, - __u32 ino, struct lu_fid *fid) + __u32 ino, struct lu_fid *fid, + struct osd_inode_id *id) { - struct osd_thread_info *info = osd_oti_get(env); - struct osd_inode_id *id = &info->oti_id; - struct inode *inode; + struct osd_thread_info *info = osd_oti_get(env); + struct inode *inode; ENTRY; osd_id_gen(id, ino, OSD_OII_NOGEN); @@ -2024,6 +2216,11 @@ static int osd_object_ea_create(const struct lu_env *env, struct dt_object *dt, LASSERT(osd_write_locked(env, obj)); LASSERT(th != NULL); + if (unlikely(fid_is_acct(fid))) + /* Quota files can't be created from the kernel any more, + * 'tune2fs -O quota' will take care of creating them */ + RETURN(-EPERM); + OSD_EXEC_OP(th, create); result = __osd_object_create(info, obj, attr, hint, dof, th); @@ -2199,22 +2396,20 @@ static int osd_declare_xattr_set(const struct lu_env *env, const struct lu_buf *buf, const char *name, int fl, struct thandle *handle) { - struct osd_thandle *oh; + struct osd_thandle *oh; - LASSERT(handle != NULL); + LASSERT(handle != NULL); - if (strcmp(name, XATTR_NAME_VERSION) == 0) { - /* no credits for version */ - return 0; - } + oh = container_of0(handle, struct osd_thandle, ot_super); + LASSERT(oh->ot_handle == NULL); - oh = container_of0(handle, struct osd_thandle, ot_super); - LASSERT(oh->ot_handle == NULL); + OSD_DECLARE_OP(oh, xattr_set); + if (strcmp(name, XATTR_NAME_VERSION) == 0) + oh->ot_credits += osd_dto_credits_noquota[DTO_ATTR_SET_BASE]; + else + oh->ot_credits += osd_dto_credits_noquota[DTO_XATTR_SET]; - OSD_DECLARE_OP(oh, xattr_set); - oh->ot_credits += osd_dto_credits_noquota[DTO_XATTR_SET]; - - return 0; + return 0; } /* @@ -2417,23 +2612,23 @@ static struct obd_capa *osd_capa_get(const struct lu_env *env, static int osd_object_sync(const struct lu_env *env, struct dt_object *dt) { - struct osd_object *obj = osd_dt_obj(dt); - struct inode *inode = obj->oo_inode; - struct osd_thread_info *info = osd_oti_get(env); - struct dentry *dentry = &info->oti_obj_dentry; - struct file *file = &info->oti_file; - int rc; + struct osd_object *obj = osd_dt_obj(dt); + struct inode *inode = obj->oo_inode; + struct osd_thread_info *info = osd_oti_get(env); + struct dentry *dentry = &info->oti_obj_dentry; + struct file *file = &info->oti_file; + int rc; - ENTRY; + ENTRY; - dentry->d_inode = inode; - file->f_dentry = dentry; - file->f_mapping = inode->i_mapping; - file->f_op = inode->i_fop; - LOCK_INODE_MUTEX(inode); - rc = file->f_op->fsync(file, dentry, 0); - UNLOCK_INODE_MUTEX(inode); - RETURN(rc); + dentry->d_inode = inode; + file->f_dentry = dentry; + file->f_mapping = inode->i_mapping; + file->f_op = inode->i_fop; + mutex_lock(&inode->i_mutex); + rc = file->f_op->fsync(file, dentry, 0); + mutex_unlock(&inode->i_mutex); + RETURN(rc); } static int osd_data_get(const struct lu_env *env, struct dt_object *dt, @@ -2492,17 +2687,6 @@ static int osd_iam_container_init(const struct lu_env *env, return result; result = iam_container_setup(bag); - if (result != 0) - goto out; - - if (osd_obj2dev(obj)->od_iop_mode) { - u32 ptr = bag->ic_descr->id_ops->id_root_ptr(bag); - - bag->ic_root_bh = ldiskfs_bread(NULL, obj->oo_inode, - ptr, 0, &result); - } - - out: if (result == 0) obj->oo_dt.do_index_ops = &osd_index_iam_ops; else @@ -2518,10 +2702,10 @@ static int osd_iam_container_init(const struct lu_env *env, static int osd_index_try(const struct lu_env *env, struct dt_object *dt, const struct dt_index_features *feat) { - int result; - int ea_dir = 0; - struct osd_object *obj = osd_dt_obj(dt); - struct osd_device *osd = osd_obj2dev(obj); + int result; + int skip_iam = 0; + struct osd_object *obj = osd_dt_obj(dt); + struct osd_device *osd = osd_obj2dev(obj); LINVRNT(osd_invariant(obj)); LASSERT(dt_object_exists(dt)); @@ -2535,10 +2719,14 @@ static int osd_index_try(const struct lu_env *env, struct dt_object *dt, result = 0; else result = -ENOTDIR; - ea_dir = 1; + skip_iam = 1; } else if (unlikely(feat == &dt_otable_features)) { dt->do_index_ops = &osd_otable_ops; return 0; + } else if (feat == &dt_acct_features) { + dt->do_index_ops = &osd_acct_index_ops; + result = 0; + skip_iam = 1; } else if (!osd_has_index(obj)) { struct osd_directory *dir; @@ -2574,7 +2762,7 @@ static int osd_index_try(const struct lu_env *env, struct dt_object *dt, result = 0; } - if (result == 0 && ea_dir == 0) { + if (result == 0 && skip_iam == 0) { if (!osd_iam_index_probe(env, obj, feat)) result = -ENOTDIR; } @@ -2583,6 +2771,15 @@ static int osd_index_try(const struct lu_env *env, struct dt_object *dt, return result; } +static int osd_otable_it_attr_get(const struct lu_env *env, + struct dt_object *dt, + struct lu_attr *attr, + struct lustre_capa *capa) +{ + attr->la_valid = 0; + return 0; +} + static const struct dt_object_operations osd_obj_ops = { .do_read_lock = osd_object_read_lock, .do_write_lock = osd_object_write_lock, @@ -2647,6 +2844,11 @@ static const struct dt_object_operations osd_obj_ea_ops = { .do_data_get = osd_data_get, }; +static const struct dt_object_operations osd_obj_otable_it_ops = { + .do_attr_get = osd_otable_it_attr_get, + .do_index_try = osd_index_try, +}; + static int osd_index_declare_iam_delete(const struct lu_env *env, struct dt_object *dt, const struct dt_key *key, @@ -3115,6 +3317,52 @@ static int osd_ea_add_rec(const struct lu_env *env, struct osd_object *pobj, return rc; } +static int +osd_consistency_check(struct osd_thread_info *oti, struct osd_device *dev, + struct osd_idmap_cache *oic) +{ + struct osd_scrub *scrub = &dev->od_scrub; + struct lu_fid *fid = &oic->oic_fid; + struct osd_inode_id *id = &oti->oti_id; + int once = 0; + int rc; + ENTRY; + +again: + rc = osd_oi_lookup(oti, dev, fid, id); + if (rc != 0 && rc != -ENOENT) + RETURN(rc); + + if (rc == 0 && osd_id_eq(id, &oic->oic_lid)) + RETURN(0); + + if (thread_is_running(&scrub->os_thread)) { + rc = osd_oii_insert(dev, oic, rc == -ENOENT); + /* There is race condition between osd_oi_lookup and OI scrub. + * The OI scrub finished just after osd_oi_lookup() failure. + * Under such case, it is unnecessary to trigger OI scrub again, + * but try to call osd_oi_lookup() again. */ + if (unlikely(rc == -EAGAIN)) + goto again; + + RETURN(rc); + } + + if (!scrub->os_no_scrub && ++once == 1) { + CDEBUG(D_LFSCK, "Trigger OI scrub by RPC for "DFID"\n", + PFID(fid)); + rc = osd_scrub_start(dev); + LCONSOLE_ERROR("%.16s: trigger OI scrub by RPC for "DFID + ", rc = %d [2]\n", + LDISKFS_SB(osd_sb(dev))->s_es->s_volume_name, + PFID(fid), rc); + if (rc == 0) + goto again; + } + + RETURN(rc = -EREMCHG); +} + /** * Calls ->lookup() to find dentry. From dentry get inode and * read inode's ea to get fid. This is required for interoperability @@ -3150,22 +3398,44 @@ static int osd_ea_lookup_rec(const struct lu_env *env, struct osd_object *obj, bh = osd_ldiskfs_find_entry(dir, dentry, &de, hlock); if (bh) { - ino = le32_to_cpu(de->inode); - rc = osd_get_fid_from_dentry(de, rec); + struct osd_thread_info *oti = osd_oti_get(env); + struct osd_idmap_cache *oic = &oti->oti_cache; + struct osd_device *dev = osd_obj2dev(obj); + struct osd_scrub *scrub = &dev->od_scrub; + struct scrub_file *sf = &scrub->os_file; + + ino = le32_to_cpu(de->inode); + rc = osd_get_fid_from_dentry(de, rec); + + /* done with de, release bh */ + brelse(bh); + if (rc != 0) + rc = osd_ea_fid_get(env, obj, ino, fid, &oic->oic_lid); + else + osd_id_gen(&oic->oic_lid, ino, OSD_OII_NOGEN); + if (rc != 0 || !fid_is_norm(fid)) { + fid_zero(&oic->oic_fid); + GOTO(out, rc); + } - /* done with de, release bh */ - brelse(bh); - if (rc != 0) - rc = osd_ea_fid_get(env, obj, ino, fid); - } else { - rc = -ENOENT; - } + oic->oic_fid = *fid; + if ((scrub->os_pos_current <= ino) && + (sf->sf_flags & SF_INCONSISTENT || + ldiskfs_test_bit(osd_oi_fid2idx(dev, fid), + sf->sf_oi_bitmap))) + rc = osd_consistency_check(oti, dev, oic); + } else { + rc = -ENOENT; + } - if (hlock != NULL) - ldiskfs_htree_unlock(hlock); - else - cfs_up_read(&obj->oo_ext_idx_sem); - RETURN (rc); + GOTO(out, rc); + +out: + if (hlock != NULL) + ldiskfs_htree_unlock(hlock); + else + cfs_up_read(&obj->oo_ext_idx_sem); + return rc; } /** @@ -3594,9 +3864,9 @@ static struct dt_it *osd_it_ea_init(const struct lu_env *env, it->oie_file.f_pos = 0; it->oie_file.f_dentry = obj_dentry; if (attr & LUDA_64BITHASH) - it->oie_file.f_flags = O_64BITHASH; + it->oie_file.f_mode |= FMODE_64BITHASH; else - it->oie_file.f_flags = O_32BITHASH; + it->oie_file.f_mode |= FMODE_32BITHASH; it->oie_file.f_mapping = obj->oo_inode->i_mapping; it->oie_file.f_op = obj->oo_inode->i_fop; it->oie_file.private_data = NULL; @@ -3781,7 +4051,7 @@ static int osd_it_ea_next(const struct lu_env *env, struct dt_it *di) it->oie_it_dirent++; RETURN(0); } else { - if (it->oie_file.f_pos == LDISKFS_HTREE_EOF) + if (it->oie_file.f_pos == ldiskfs_get_htree_eof(&it->oie_file)) rc = +1; else rc = osd_ldiskfs_it_fill(env, di); @@ -3832,27 +4102,46 @@ static int osd_it_ea_key_size(const struct lu_env *env, const struct dt_it *di) * \retval -ve on error */ static inline int osd_it_ea_rec(const struct lu_env *env, - const struct dt_it *di, - struct dt_rec *dtrec, __u32 attr) -{ - struct osd_it_ea *it = (struct osd_it_ea *)di; - struct osd_object *obj = it->oie_obj; - struct lu_fid *fid = &it->oie_dirent->oied_fid; - struct lu_dirent *lde = (struct lu_dirent *)dtrec; - int rc = 0; + const struct dt_it *di, + struct dt_rec *dtrec, __u32 attr) +{ + struct osd_it_ea *it = (struct osd_it_ea *)di; + struct osd_object *obj = it->oie_obj; + struct osd_device *dev = osd_obj2dev(obj); + struct osd_scrub *scrub = &dev->od_scrub; + struct scrub_file *sf = &scrub->os_file; + struct osd_thread_info *oti = osd_oti_get(env); + struct osd_idmap_cache *oic = &oti->oti_cache; + struct lu_fid *fid = &it->oie_dirent->oied_fid; + struct lu_dirent *lde = (struct lu_dirent *)dtrec; + __u32 ino = it->oie_dirent->oied_ino; + int rc = 0; + ENTRY; - ENTRY; + if (!fid_is_sane(fid)) { + rc = osd_ea_fid_get(env, obj, ino, fid, &oic->oic_lid); + if (rc != 0) + RETURN(rc); + } else { + osd_id_gen(&oic->oic_lid, ino, OSD_OII_NOGEN); + } - if (!fid_is_sane(fid)) - rc = osd_ea_fid_get(env, obj, it->oie_dirent->oied_ino, fid); + osd_it_pack_dirent(lde, fid, it->oie_dirent->oied_off, + it->oie_dirent->oied_name, + it->oie_dirent->oied_namelen, + it->oie_dirent->oied_type, attr); + if (!fid_is_norm(fid)) { + fid_zero(&oic->oic_fid); + RETURN(0); + } - if (rc == 0) - osd_it_pack_dirent(lde, fid, it->oie_dirent->oied_off, - it->oie_dirent->oied_name, - it->oie_dirent->oied_namelen, - it->oie_dirent->oied_type, - attr); - RETURN(rc); + oic->oic_fid = *fid; + if ((scrub->os_pos_current <= ino) && + (sf->sf_flags & SF_INCONSISTENT || + ldiskfs_test_bit(osd_oi_fid2idx(dev, fid), sf->sf_oi_bitmap))) + rc = osd_consistency_check(oti, dev, oic); + + RETURN(rc); } /** @@ -4013,7 +4302,10 @@ struct lu_context_key osd_key = { static int osd_device_init(const struct lu_env *env, struct lu_device *d, const char *name, struct lu_device *next) { - return osd_procfs_init(osd_dev(d), name); + struct osd_device *osd = osd_dev(d); + + strncpy(osd->od_svname, name, MAX_OBD_NAME); + return osd_procfs_init(osd, name); } static int osd_shutdown(const struct lu_env *env, struct osd_device *o) @@ -4024,7 +4316,13 @@ static int osd_shutdown(const struct lu_env *env, struct osd_device *o) if (o->od_fsops) { fsfilt_put_ops(o->od_fsops); - o->od_fsops = NULL; + o->od_fsops = NULL; + } + + /* shutdown quota slave instance associated with the device */ + if (o->od_quota_slave != NULL) { + qsd_fini(env, o->od_quota_slave); + o->od_quota_slave = NULL; } RETURN(0); @@ -4165,6 +4463,7 @@ static int osd_process_config(const struct lu_env *env, err = osd_mount(env, o, cfg); break; case LCFG_CLEANUP: + lu_dev_del_linkage(d->ld_site, d); err = osd_shutdown(env, o); break; default: @@ -4192,10 +4491,36 @@ static int osd_prepare(const struct lu_env *env, struct lu_device *pdev, if (result < 0) RETURN(result); - if (!lu_device_is_md(pdev)) + /* 2. setup quota slave instance */ + osd->od_quota_slave = qsd_init(env, osd->od_svname, &osd->od_dt_dev, + osd->od_proc_entry); + if (IS_ERR(osd->od_quota_slave)) { + result = PTR_ERR(osd->od_quota_slave); + osd->od_quota_slave = NULL; + RETURN(result); + } + +#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 3, 55, 0) + /* Unfortunately, the current MDD implementation relies on some specific + * code to be executed in the OSD layer. Since OFD now also uses the OSD + * module, we need a way to skip the metadata-specific code when running + * with OFD. + * The hack here is to check the type of the parent device which is + * either MD (i.e. MDD device) with the current MDT stack or DT (i.e. + * OFD device) on an OST. As a reminder, obdfilter does not use the OSD + * layer and still relies on lvfs. This hack won't work any more when + * LOD is landed since LOD is of DT type. + * This code should be removed once the orion MDT changes (LOD/OSP, ...) + * have been landed */ + osd->od_is_md = lu_device_is_md(pdev); +#else +#warning "all is_md checks must be removed from osd-ldiskfs" +#endif + + if (!osd->od_is_md) RETURN(0); - /* 2. setup local objects */ + /* 3. setup local objects */ result = llo_local_objects_setup(env, lu2md_dev(pdev), lu2dt_dev(dev)); RETURN(result); }