module_param(ldiskfs_track_declares_assert, int, 0644);
MODULE_PARM_DESC(ldiskfs_track_declares_assert, "LBUG during tracking of declares");
+/* 1 GiB in 512-byte sectors */
+int ldiskfs_delayed_unlink_blocks = (1 << (30 - 9));
+
/* Slab to allocate dynlocks */
struct kmem_cache *dynlock_cachep;
return 0;
}
+struct osd_delayed_iput_work {
+ struct work_struct diw_work;
+ struct inode *diw_inode;
+};
+
+static void osd_delayed_iput_fn(struct work_struct *work)
+{
+ struct osd_delayed_iput_work *diwork;
+ struct inode *inode;
+
+ diwork = container_of(work, struct osd_delayed_iput_work, diw_work);
+ inode = diwork->diw_inode;
+ CDEBUG(D_INODE, "%s: delayed iput (ino=%lu)\n",
+ inode->i_sb->s_id, inode->i_ino);
+ iput(inode);
+ OBD_FREE_PTR(diwork);
+}
+
+noinline void osd_delayed_iput(struct inode *inode,
+ struct osd_delayed_iput_work *diwork)
+{
+ if (!diwork) {
+ iput(inode);
+ } else {
+ INIT_WORK(&diwork->diw_work, osd_delayed_iput_fn);
+ diwork->diw_inode = inode;
+ queue_work(LDISKFS_SB(inode->i_sb)->s_misc_wq,
+ &diwork->diw_work);
+ }
+}
+
/*
* Called just before object is freed. Releases all resources except for
* object itself (that is released by osd_object_free()).
struct osd_object *obj = osd_obj(l);
struct qsd_instance *qsd = osd_def_qsd(osd_obj2dev(obj));
struct inode *inode = obj->oo_inode;
+ struct osd_delayed_iput_work *diwork = NULL;
__u64 projid;
qid_t uid;
qid_t gid;
if (!inode)
return;
+ if (inode->i_blocks > ldiskfs_delayed_unlink_blocks)
+ OBD_ALLOC(diwork, sizeof(*diwork));
+
if (osd_has_index(obj) && obj->oo_dt.do_index_ops == &osd_index_iam_ops)
ldiskfs_set_inode_flag(inode, LDISKFS_INODE_JOURNAL_DATA);
projid = i_projid_read(inode);
obj->oo_inode = NULL;
- iput(inode);
+ osd_delayed_iput(inode, diwork);
/* do not rebalance quota if the caller needs to release memory
* otherwise qsd_refresh_usage() may went into a new ldiskfs
.o_health_check = osd_health_check,
};
+static ssize_t delayed_unlink_mb_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ldiskfs_delayed_unlink_blocks >> 11);
+}
+
+static ssize_t delayed_unlink_mb_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ u64 delayed_unlink_bytes;
+ int rc;
+
+ rc = sysfs_memparse(buffer, count, &delayed_unlink_bytes, "MiB");
+ if (rc)
+ return rc;
+
+ ldiskfs_delayed_unlink_blocks = delayed_unlink_bytes >> 9;
+
+ return count;
+}
+LUSTRE_RW_ATTR(delayed_unlink_mb);
+
+
static ssize_t track_declares_assert_show(struct kobject *kobj,
struct attribute *attr,
char *buf)
if (kobj) {
rc = sysfs_create_file(kobj,
&lustre_attr_track_declares_assert.attr);
- kobject_put(kobj);
if (rc) {
- CWARN("osd-ldiskfs: track_declares_assert failed to register with sysfs\n");
+ CWARN("%s: track_declares_assert sysfs registration failed: rc = %d\n",
+ "osd-ldiskfs", rc);
rc = 0;
}
+
+ rc = sysfs_create_file(kobj,
+ &lustre_attr_delayed_unlink_mb.attr);
+ if (rc) {
+ CWARN("%s: delayed_unlink_mb registration failed: rc = %d\n",
+ "osd-ldiskfs", rc);
+ rc = 0;
+ }
+
+ kobject_put(kobj);
}
#ifndef HAVE_FLUSH_DELAYED_FPUT
ssize_t force_sync_store(struct kobject *kobj, struct attribute *attr,
const char *buffer, size_t count)
{
- struct dt_device *dt = container_of(kobj, struct dt_device,
- dd_kobj);
+ struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj);
struct osd_device *osd = osd_dt_dev(dt);
- struct lu_env env;
int rc;
LASSERT(osd);
if (unlikely(!osd->od_mnt))
return -EINPROGRESS;
- rc = lu_env_init(&env, LCT_LOCAL);
- if (rc)
- return rc;
-
- rc = dt_sync(&env, dt);
- lu_env_fini(&env);
+ flush_workqueue(LDISKFS_SB(osd_sb(osd_dt_dev(dt)))->s_misc_wq);
+ rc = dt_sync(NULL, dt);
return rc == 0 ? count : rc;
}
}
run_test 319 "lost lease lock on migrate error"
+test_360() {
+ (( $OST1_VERSION >= $(version_code 2.15.58.96) )) ||
+ skip "Need OST version at least 2.15.58.96"
+ [[ "$ost1_FSTYPE" == "ldiskfs" ]] || skip "ldiskfs only test"
+
+ check_set_fallocate_or_skip
+ do_facet ost1 "$LCTL set_param osd-ldiskfs.delayed_unlink_mb=1MiB"
+
+ mkdir $DIR/$tdir/
+ do_facet ost1 $LCTL set_param debug=+inode
+ do_facet ost1 $LCTL clear
+ local files=100
+
+ for ((i = 0; i < $files; i++)); do
+ fallocate -l 1280k $DIR/$tdir/$tfile.$i ||
+ error "fallocate 1280k $DIR/$tdir/$tfile.$i failed"
+ done
+ local min=$(($($LFS find $DIR/$tdir --ost 0 | wc -l) / 2))
+
+ for ((i = 0; i < $files; i++)); do
+ unlink $DIR/$tdir/$tfile.$i ||
+ error "unlink $DIR/$tdir/$tfile.$i failed"
+ done
+
+ local count=0
+ local loop
+
+ for (( loop = 0; loop < 30 && count < min; loop++)); do
+ sleep 1
+ (( count += $(do_facet ost1 $LCTL dk | grep -c "delayed iput")))
+ echo "Count[$loop]: $count"
+ done
+ (( count >= min )) || error "$count < $min delayed iput after $loop s"
+}
+run_test 360 "ldiskfs unlink in a separate thread"
+
test_398a() { # LU-4198
local ost1_imp=$(get_osc_import_name client ost1)
local imp_name=$($LCTL list_param osc.$ost1_imp | head -n1 |