__u32 op_archive_id;
};
-struct md_callback {
- int (*md_blocking_ast)(struct ldlm_lock *lock,
+struct md_readdir_info {
+ int (*mr_blocking_ast)(struct ldlm_lock *lock,
struct ldlm_lock_desc *desc,
void *data, int flag);
+ /* if striped directory is partially read, the result is stored here */
+ int mr_partial_readdir_rc;
};
struct md_enqueue_info;
struct ptlrpc_request **);
int (*m_read_page)(struct obd_export *, struct md_op_data *,
- struct md_callback *cb_op, __u64 hash_offset,
+ struct md_readdir_info *mrinfo, __u64 hash_offset,
struct page **ppage);
int (*m_unlink)(struct obd_export *, struct md_op_data *,
static inline int md_read_page(struct obd_export *exp,
struct md_op_data *op_data,
- struct md_callback *cb_op,
- __u64 hash_offset,
- struct page **ppage)
+ struct md_readdir_info *mrinfo,
+ __u64 hash_offset, struct page **ppage)
{
int rc;
lprocfs_counter_incr(exp->exp_obd->obd_md_stats,
LPROC_MD_READ_PAGE);
- return MDP(exp->exp_obd, read_page)(exp, op_data, cb_op, hash_offset,
+ return MDP(exp->exp_obd, read_page)(exp, op_data, mrinfo, hash_offset,
ppage);
}
*
*/
struct page *ll_get_dir_page(struct inode *dir, struct md_op_data *op_data,
- __u64 offset)
+ __u64 offset, int *partial_readdir_rc)
{
- struct md_callback cb_op;
- struct page *page;
- int rc;
+ struct md_readdir_info mrinfo = {
+ .mr_blocking_ast = ll_md_blocking_ast };
+ struct page *page;
+ int rc;
- cb_op.md_blocking_ast = ll_md_blocking_ast;
- rc = md_read_page(ll_i2mdexp(dir), op_data, &cb_op, offset, &page);
+ rc = md_read_page(ll_i2mdexp(dir), op_data, &mrinfo, offset, &page);
if (rc != 0)
return ERR_PTR(rc);
+ if (partial_readdir_rc && mrinfo.mr_partial_readdir_rc)
+ *partial_readdir_rc = mrinfo.mr_partial_readdir_rc;
+
return page;
}
#ifdef HAVE_DIR_CONTEXT
int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
- struct dir_context *ctx)
+ struct dir_context *ctx, int *partial_readdir_rc)
{
#else
int ll_dir_read(struct inode *inode, __u64 *ppos, struct md_op_data *op_data,
- void *cookie, filldir_t filldir)
+ void *cookie, filldir_t filldir, int *partial_readdir_rc)
{
#endif
struct ll_sb_info *sbi = ll_i2sbi(inode);
RETURN(rc);
}
- page = ll_get_dir_page(inode, op_data, pos);
+ page = ll_get_dir_page(inode, op_data, pos, partial_readdir_rc);
while (rc == 0 && !done) {
struct lu_dirpage *dp;
le32_to_cpu(dp->ldp_flags) &
LDF_COLLIDE);
next = pos;
- page = ll_get_dir_page(inode, op_data, pos);
+ page = ll_get_dir_page(inode, op_data, pos,
+ partial_readdir_rc);
}
}
#ifdef HAVE_DIR_CONTEXT
struct md_op_data *op_data;
struct lu_fid pfid = { 0 };
ktime_t kstart = ktime_get();
+ /* result of possible partial readdir */
+ int partial_readdir_rc = 0;
__u64 pos;
int rc;
+
ENTRY;
- if (lfd != NULL)
- pos = lfd->lfd_pos;
- else
- pos = 0;
+ LASSERT(lfd != NULL);
+ pos = lfd->lfd_pos;
CDEBUG(D_VFSTRACE,
"VFS Op:inode="DFID"(%p) pos/size%lu/%llu 32bit_api %d\n",
#ifdef HAVE_DIR_CONTEXT
ctx->pos = pos;
- rc = ll_dir_read(inode, &pos, op_data, ctx);
+ rc = ll_dir_read(inode, &pos, op_data, ctx, &partial_readdir_rc);
pos = ctx->pos;
#else
- rc = ll_dir_read(inode, &pos, op_data, cookie, filldir);
+ rc = ll_dir_read(inode, &pos, op_data, cookie, filldir,
+ &partial_readdir_rc);
#endif
- if (lfd != NULL)
- lfd->lfd_pos = pos;
+ lfd->lfd_pos = pos;
+ if (!lfd->fd_partial_readdir_rc)
+ lfd->fd_partial_readdir_rc = partial_readdir_rc;
if (pos == MDS_DIR_END_OFF) {
if (api32)
RETURN(ll_file_release(inode, file));
}
+/* notify error if partially read striped directory */
+static int ll_dir_flush(struct file *file, fl_owner_t id)
+{
+ struct ll_file_data *lfd = file->private_data;
+ int rc = lfd->fd_partial_readdir_rc;
+
+ lfd->fd_partial_readdir_rc = 0;
+
+ return rc;
+}
+
const struct file_operations ll_dir_operations = {
.llseek = ll_dir_seek,
.open = ll_dir_open,
#endif
.unlocked_ioctl = ll_dir_ioctl,
.fsync = ll_fsync,
+ .flush = ll_dir_flush,
};
* layout version for verification to OST objects */
__u32 fd_layout_version;
struct pcc_file fd_pcc_file;
+ /* striped directory may read partially if some stripe inaccessible,
+ * -errno is saved here, and will return to user in close().
+ */
+ int fd_partial_readdir_rc;
};
void llite_tunables_unregister(void);
extern const struct inode_operations ll_dir_inode_operations;
#ifdef HAVE_DIR_CONTEXT
int ll_dir_read(struct inode *inode, __u64 *pos, struct md_op_data *op_data,
- struct dir_context *ctx);
+ struct dir_context *ctx, int *partial_readdir_rc);
#else
int ll_dir_read(struct inode *inode, __u64 *pos, struct md_op_data *op_data,
- void *cookie, filldir_t filldir);
+ void *cookie, filldir_t filldir, int *partial_readdir_rc);
#endif
int ll_get_mdt_idx(struct inode *inode);
int ll_get_mdt_idx_by_fid(struct ll_sb_info *sbi, const struct lu_fid *fid);
struct page *ll_get_dir_page(struct inode *dir, struct md_op_data *op_data,
- __u64 offset);
+ __u64 offset, int *partial_readdir_rc);
void ll_release_page(struct inode *inode, struct page *page, bool remove);
int quotactl_ioctl(struct super_block *sb, struct if_quotactl *qctl);
inode_lock(dir);
#ifdef HAVE_DIR_CONTEXT
- rc = ll_dir_read(dir, &pos, op_data, &lgd.ctx);
+ rc = ll_dir_read(dir, &pos, op_data, &lgd.ctx, NULL);
#else
- rc = ll_dir_read(dir, &pos, op_data, &lgd, ll_nfs_get_name_filldir);
+ rc = ll_dir_read(dir, &pos, op_data, &lgd, ll_nfs_get_name_filldir,
+ NULL);
#endif
inode_unlock(dir);
ll_finish_md_op_data(op_data);
}
sai->sai_in_readpage = 1;
- page = ll_get_dir_page(dir, op_data, pos);
+ page = ll_get_dir_page(dir, op_data, pos, NULL);
ll_unlock_md_op_lsm(op_data);
sai->sai_in_readpage = 0;
if (IS_ERR(page)) {
*FIXME choose the start offset of the readdir
*/
- page = ll_get_dir_page(dir, op_data, 0);
+ page = ll_get_dir_page(dir, op_data, 0, NULL);
while (1) {
struct lu_dirpage *dp;
*/
ll_release_page(dir, page, le32_to_cpu(dp->ldp_flags) &
LDF_COLLIDE);
- page = ll_get_dir_page(dir, op_data, pos);
+ page = ll_get_dir_page(dir, op_data, pos, NULL);
}
}
EXIT;
rc = md_intent_lock(tgt->ltd_exp, op_data, &it, &req,
cb_blocking, extra_lock_flags);
- if (rc == -ENOENT) {
- /* skip stripe is not exists */
+ if (rc == -ENOENT || rc == -ESHUTDOWN) {
+ /* skip stripe that doesn't exist or is inaccessible */
rc = 0;
continue;
}
struct lmv_dir_ctxt {
struct lmv_obd *ldc_lmv;
struct md_op_data *ldc_op_data;
- struct md_callback *ldc_cb_op;
+ struct md_readdir_info *ldc_mrinfo;
__u64 ldc_hash;
int ldc_count;
struct stripe_dirent ldc_stripes[0];
op_data->op_fid2 = oinfo->lmo_fid;
op_data->op_data = oinfo->lmo_root;
- rc = md_read_page(tgt->ltd_exp, op_data, ctxt->ldc_cb_op, hash,
+ rc = md_read_page(tgt->ltd_exp, op_data, ctxt->ldc_mrinfo, hash,
&stripe->sd_page);
op_data->op_fid1 = fid;
LASSERT(!ent);
/* treat error as eof, so dir can be partially accessed */
stripe->sd_eof = true;
+ ctxt->ldc_mrinfo->mr_partial_readdir_rc = rc;
LCONSOLE_WARN("dir "DFID" stripe %d readdir failed: %d, "
"directory is partially accessed!\n",
PFID(&ctxt->ldc_op_data->op_fid1), stripe_index,
*
* \param[in] exp obd export refer to LMV
* \param[in] op_data hold those MD parameters of read_entry
- * \param[in] cb_op ldlm callback being used in enqueue in mdc_read_entry
+ * \param[in] mrinfo ldlm callback being used in enqueue in mdc_read_entry,
+ * and partial readdir result will be stored in it.
* \param[in] offset starting hash offset
* \param[out] ppage the page holding the entry. Note: because the entry
* will be accessed in upper layer, so we need hold the
*/
static int lmv_striped_read_page(struct obd_export *exp,
struct md_op_data *op_data,
- struct md_callback *cb_op,
- __u64 offset, struct page **ppage)
+ struct md_readdir_info *mrinfo, __u64 offset,
+ struct page **ppage)
{
struct page *page = NULL;
struct lu_dirpage *dp;
GOTO(free_page, rc = -ENOMEM);
ctxt->ldc_lmv = &exp->exp_obd->u.lmv;
ctxt->ldc_op_data = op_data;
- ctxt->ldc_cb_op = cb_op;
+ ctxt->ldc_mrinfo = mrinfo;
ctxt->ldc_hash = offset;
ctxt->ldc_count = stripe_count;
}
static int lmv_read_page(struct obd_export *exp, struct md_op_data *op_data,
- struct md_callback *cb_op, __u64 offset,
+ struct md_readdir_info *mrinfo, __u64 offset,
struct page **ppage)
{
struct obd_device *obd = exp->exp_obd;
RETURN(-ENODATA);
if (unlikely(lmv_dir_striped(op_data->op_mea1))) {
- rc = lmv_striped_read_page(exp, op_data, cb_op, offset, ppage);
+ rc = lmv_striped_read_page(exp, op_data, mrinfo, offset, ppage);
RETURN(rc);
}
if (IS_ERR(tgt))
RETURN(PTR_ERR(tgt));
- rc = md_read_page(tgt->ltd_exp, op_data, cb_op, offset, ppage);
+ rc = md_read_page(tgt->ltd_exp, op_data, mrinfo, offset, ppage);
RETURN(rc);
}
__u64 rp_off;
int rp_hash64;
struct obd_export *rp_exp;
- struct md_callback *rp_cb;
};
/**
* \param[in] exp MDC export
* \param[in] op_data client MD stack parameters, transfering parameters
* between different layers on client MD stack.
- * \param[in] cb_op callback required for ldlm lock enqueue during
+ * \param[in] mrinfo callback required for ldlm lock enqueue during
* read page
* \param[in] hash_offset the hash offset of the page to be read
* \param[in] ppage the page to be read
* errno(<0) get the page failed
*/
static int mdc_read_page(struct obd_export *exp, struct md_op_data *op_data,
- struct md_callback *cb_op, __u64 hash_offset,
+ struct md_readdir_info *mrinfo, __u64 hash_offset,
struct page **ppage)
{
struct lookup_intent it = { .it_op = IT_READDIR };
mapping = dir->i_mapping;
rc = mdc_intent_lock(exp, op_data, &it, &enq_req,
- cb_op->md_blocking_ast, 0);
+ mrinfo->mr_blocking_ast, 0);
if (enq_req != NULL)
ptlrpc_req_finished(enq_req);
}
run_test 33h "temp file is located on the same MDT as target"
+test_33i()
+{
+ (( MDSCOUNT < 2 )) && skip "needs >= 2 MDTs"
+
+ local FNAME=$(str_repeat 'f' 250)
+
+ test_mkdir -i 0 -c $MDSCOUNT $DIR/$tdir || error "mkdir $tdir failed"
+ createmany -o $DIR/$tdir/$FNAME 1000 || error "createmany failed"
+
+ local count
+ local total
+
+ count=$($LFS getstripe -m $DIR/$tdir/* | grep -cw 1)
+
+ local MDC=$(lctl dl | awk '/MDT0001-mdc-[^M]/ { print $4 }')
+
+ lctl --device %$MDC deactivate
+ stack_trap "lctl --device %$MDC activate"
+ ls $DIR/$tdir > /dev/null && error "ls should return an error"
+ total=$(\ls -l $DIR/$tdir | wc -l)
+ # "ls -l" will list total in the first line
+ total=$((total - 1))
+ (( total + count == 1000 )) ||
+ error "ls list $total files, $count files on MDT1"
+}
+run_test 33i "striped directory can be accessed when one MDT is down"
+
TEST_34_SIZE=${TEST_34_SIZE:-2000000000000}
test_34a() {
rm -f $DIR/f34
awk '/^status/ { print \\\$2 }'" "completed"
done
- ls -R $DIR/$tdir || error "ls failed"
+ ls -R $DIR/$tdir
rm -rf $DIR/$tdir || error "rmdir failed"
}
run_test 60g "transaction abort won't cause MDT hung"
}
run_test 300s "test lfs mkdir -c without -i"
-
prepare_remote_file() {
mkdir $DIR/$tdir/src_dir ||
error "create remote source failed"