#include <linux/poll.h>
#include <linux/device.h>
#include <linux/cdev.h>
+#include <linux/idr.h>
#include <lustre_log.h>
#include <uapi/linux/lustre/lustre_ioctl.h>
char ced_name[32];
/* changelog char device */
struct cdev ced_cdev;
- struct device *ced_device;
+ struct device ced_device;
/* OBDs referencing this device (multiple mount point) */
struct list_head ced_obds;
/* Reference counter for proper deregistration */
CDEV_CHLG_MAX_PREFETCH = 1024,
};
-static DEFINE_IDR(chlg_minor_idr);
+DEFINE_IDR(mdc_changelog_minor_idr);
static DEFINE_SPINLOCK(chlg_minor_lock);
static int chlg_minor_alloc(int *pminor)
idr_preload(GFP_KERNEL);
spin_lock(&chlg_minor_lock);
- minor = idr_alloc(&chlg_minor_idr, minor_allocated, 0,
+ minor = idr_alloc(&mdc_changelog_minor_idr, minor_allocated, 0,
MDC_CHANGELOG_DEV_COUNT, GFP_NOWAIT);
spin_unlock(&chlg_minor_lock);
idr_preload_end();
static void chlg_minor_free(int minor)
{
spin_lock(&chlg_minor_lock);
- idr_remove(&chlg_minor_idr, minor);
+ idr_remove(&mdc_changelog_minor_idr, minor);
spin_unlock(&chlg_minor_lock);
}
static void chlg_dev_clear(struct kref *kref)
{
struct chlg_registered_dev *entry;
-
+
ENTRY;
entry = container_of(kref, struct chlg_registered_dev,
ced_refs);
list_del(&entry->ced_link);
- cdev_del(&entry->ced_cdev);
- device_destroy(mdc_changelog_class, entry->ced_cdev.dev);
+ cdev_device_del(&entry->ced_cdev, &entry->ced_device);
+ put_device(&entry->ced_device);
EXIT;
}
if (rec->cr_hdr.lrh_type != CHANGELOG_REC) {
rc = -EINVAL;
- CERROR("%s: not a changelog rec %x/%d in llog "DFID" rc = %d\n",
+ CERROR("%s: not a changelog rec %x/%d in llog : rc = %d\n",
crs->crs_obd->obd_name, rec->cr_hdr.lrh_type,
- rec->cr.cr_type,
- PFID(lu_object_fid(&llh->lgh_obj->do_lu)), rc);
+ rec->cr.cr_type, rc);
RETURN(rc);
}
+ /* Check if we can skip the entire llog plain */
+ if (llog_is_plain_skipable(llh->lgh_hdr, hdr, rec->cr.cr_index,
+ crs->crs_start_offset))
+ RETURN(LLOG_SKIP_PLAIN);
+
/* Skip undesired records */
if (rec->cr.cr_index < crs->crs_start_offset)
RETURN(0);
crs->crs_rec_count++;
mutex_unlock(&crs->crs_lock);
- wake_up_all(&crs->crs_waitq_cons);
+ wake_up(&crs->crs_waitq_cons);
RETURN(0);
}
int rc;
ENTRY;
- crs->crs_last_catidx = -1;
+ crs->crs_last_catidx = 0;
crs->crs_last_idx = 0;
again:
if (rc < 0)
crs->crs_err = rc;
- wake_up_all(&crs->crs_waitq_cons);
+ wake_up(&crs->crs_waitq_cons);
if (llh != NULL)
llog_cat_close(NULL, llh);
RETURN(rc);
}
+static int chlg_start_thread(struct file *file)
+{
+ struct chlg_reader_state *crs = file->private_data;
+ struct task_struct *task;
+ int rc = 0;
+
+ if (likely(crs->crs_prod_task))
+ return 0;
+ if (unlikely(file->f_mode & FMODE_READ) == 0)
+ return 0;
+
+ mutex_lock(&crs->crs_lock);
+ if (crs->crs_prod_task == NULL) {
+ task = kthread_run(chlg_load, crs, "chlg_load_thread");
+ if (IS_ERR(task)) {
+ rc = PTR_ERR(task);
+ CERROR("%s: cannot start changelog thread: rc = %d\n",
+ crs->crs_ced->ced_name, rc);
+ GOTO(out, rc);
+ }
+ crs->crs_prod_task = task;
+ }
+out:
+ mutex_unlock(&crs->crs_lock);
+ return rc;
+}
+
/**
* Read handler, dequeues records from the chlg_reader_state if any.
* No partial records are copied to userland so this function can return less
RETURN(-EAGAIN);
}
+ rc = chlg_start_thread(file);
+ if (rc)
+ RETURN(rc);
+
rc = wait_event_interruptible(crs->crs_waitq_cons,
crs->crs_rec_count > 0 || crs->crs_eof || crs->crs_err);
if (written_total > 0) {
rc = written_total;
- wake_up_all(&crs->crs_waitq_prod);
+ wake_up(&crs->crs_waitq_prod);
} else if (rc == 0) {
rc = crs->crs_err;
}
}
mutex_unlock(&crs->crs_lock);
- wake_up_all(&crs->crs_waitq_prod);
+ wake_up(&crs->crs_waitq_prod);
return 0;
}
{
struct chlg_reader_state *crs;
struct chlg_registered_dev *dev;
- struct task_struct *task;
- int rc;
ENTRY;
dev = container_of(inode->i_cdev, struct chlg_registered_dev, ced_cdev);
INIT_LIST_HEAD(&crs->crs_rec_queue);
init_waitqueue_head(&crs->crs_waitq_prod);
init_waitqueue_head(&crs->crs_waitq_cons);
-
- if (file->f_mode & FMODE_READ) {
- task = kthread_run(chlg_load, crs, "chlg_load_thread");
- if (IS_ERR(task)) {
- rc = PTR_ERR(task);
- CERROR("%s: cannot start changelog thread: rc = %d\n",
- dev->ced_name, rc);
- GOTO(err_crs, rc);
- }
- crs->crs_prod_task = task;
- }
+ crs->crs_prod_task = NULL;
file->private_data = crs;
RETURN(0);
-
-err_crs:
- kref_put(&dev->ced_refs, chlg_dev_clear);
- OBD_FREE_PTR(crs);
- return rc;
}
/**
{
struct chlg_reader_state *crs = file->private_data;
unsigned int mask = 0;
+ int rc;
+
+ rc = chlg_start_thread(file);
+ if (rc)
+ RETURN(rc);
mutex_lock(&crs->crs_lock);
poll_wait(file, &crs->crs_waitq_cons, wait);
{
struct chlg_registered_dev *exist;
struct chlg_registered_dev *entry;
- struct device *device;
- dev_t dev;
int minor, rc;
ENTRY;
list_add_tail(&obd->u.cli.cl_chg_dev_linkage, &entry->ced_obds);
list_add_tail(&entry->ced_link, &chlg_registered_devices);
- /* Register new character device */
- cdev_init(&entry->ced_cdev, &chlg_fops);
- entry->ced_cdev.owner = THIS_MODULE;
-
rc = chlg_minor_alloc(&minor);
if (rc)
- GOTO(out_unlock, rc);
-
- dev = MKDEV(MAJOR(mdc_changelog_dev), minor);
- rc = cdev_add(&entry->ced_cdev, dev, 1);
+ GOTO(out_listrm, rc);
+
+ device_initialize(&entry->ced_device);
+ entry->ced_device.devt = MKDEV(MAJOR(mdc_changelog_dev), minor);
+ entry->ced_device.class = mdc_changelog_class;
+ entry->ced_device.release = chlg_device_release;
+ dev_set_drvdata(&entry->ced_device, entry);
+ rc = dev_set_name(&entry->ced_device, "%s-%s", MDC_CHANGELOG_DEV_NAME,
+ entry->ced_name);
if (rc)
GOTO(out_minor, rc);
- device = device_create(mdc_changelog_class, NULL, dev, entry, "%s-%s",
- MDC_CHANGELOG_DEV_NAME, entry->ced_name);
- if (IS_ERR(device))
- GOTO(out_cdev, rc = PTR_ERR(device));
-
- device->release = chlg_device_release;
- entry->ced_device = device;
+ /* Register new character device */
+ cdev_init(&entry->ced_cdev, &chlg_fops);
+ entry->ced_cdev.owner = THIS_MODULE;
+ rc = cdev_device_add(&entry->ced_cdev, &entry->ced_device);
+ if (rc)
+ GOTO(out_device_name, rc);
entry = NULL; /* prevent it from being freed below */
GOTO(out_unlock, rc = 0);
-out_cdev:
- cdev_del(&entry->ced_cdev);
+out_device_name:
+ kfree_const(entry->ced_device.kobj.name);
out_minor:
chlg_minor_free(minor);
+out_listrm:
list_del_init(&obd->u.cli.cl_chg_dev_linkage);
list_del(&entry->ced_link);