* OBDFS Super operations - also used for Lustre file system
*
*
+ * This code is issued under the GNU General Public License.
+ * See the file COPYING in this distribution
+ *
* Copyright (C) 1991, 1992 Linus Torvalds
* Copryright (C) 1999 Stelias Computing Inc. <braam@stelias.com>
* Copryright (C) 1999 Seagate Technology Inc.
*/
#define nr_free_buffer_pages() 32768
-struct {
+/* Defines for page buf daemon */
+struct pupd_prm {
int nfract; /* Percentage of buffer cache dirty to
activate bdflush */
int ndirty; /* Maximum number of dirty blocks to write out per
int interval; /* jiffies delay between pupdate flushes */
int age_buffer; /* Time for normal buffer to age before we flush it */
int age_super; /* Time for superblock to age before we flush it */
-} pupd_prm = {40, 1024, 64, 256, 1*HZ, 30*HZ, 5*HZ };
+};
+
+
+static struct pupdated {
+ int active;
+ wait_queue_head_t waitq;
+ struct timer_list timer;
+ struct pupd_prm parms;
+} pupdated = {
+ active: -1,
+ parms: {40, 1024, 64, 256, 1*HZ, 30*HZ, 5*HZ }
+};
+
/* Called with the superblock list lock held */
static int obdfs_enqueue_pages(struct inode *inode, struct obdo **obdo,
EXIT;
}
+/* This value is not arbitrarily chosen. KIO_STATIC_PAGES from linux/iobuf.h */
+#define MAX_IOVEC (KIO_STATIC_PAGES - 1)
+
/* Remove writeback requests for the superblock */
int obdfs_flush_reqs(struct list_head *inode_list, unsigned long check_time)
{
}
/* If we are forcing a write, write out all dirty pages */
- max_io = check_time == ~0UL ? 1<<31 : pupd_prm.ndirty;
+ max_io = check_time == ~0UL ? 1<<31 : pupdated.parms.ndirty;
CDEBUG(D_INFO, "max_io = %lu\n", max_io);
/* Add each inode's dirty pages to a write vector, and write it.
} /* obdfs_flush_dirty_pages */
-static struct task_struct *pupdated;
+static void pupdate_wakeup(unsigned long l)
+{
+ wake_up_interruptible(&pupdated.waitq);
+}
+
static int pupdate(void *unused)
{
- int interval = pupd_prm.interval;
- long age = pupd_prm.age_buffer;
+ u_long flags;
+ int interval = pupdated.parms.interval;
+ long age = pupdated.parms.age_buffer;
int wrote = 0;
+
+ if (pupdated.active >= 0) {
+ CDEBUG(D_CACHE, "attempted to run multiple pupdates\n");
+ return 1;
+ }
+
+ init_timer(&pupdated.timer);
+ init_waitqueue_head(&pupdated.waitq);
+ pupdated.timer.function = pupdate_wakeup;
exit_files(current);
exit_mm(current);
+ daemonize();
- pupdated = current;
- pupdated->session = 1;
- pupdated->pgrp = 1;
- strcpy(pupdated->comm, "pupdated");
+ current->session = 1;
+ current->pgrp = 1;
+ strcpy(current->comm, "pupdated");
- printk("pupdated activated...\n");
+ CDEBUG(D_CACHE, "pupdated activated...\n");
+ pupdated.active = 1;
- spin_lock_irq(&pupdated->sigmask_lock);
- sigfillset(&pupdated->blocked);
- siginitsetinv(&pupdated->blocked, sigmask(SIGTERM));
- recalc_sigpending(pupdated);
- spin_unlock_irq(&pupdated->sigmask_lock);
+ spin_lock_irqsave(¤t->sigmask_lock, flags);
+ flush_signals(current);
+ sigfillset(¤t->blocked);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(¤t->sigmask_lock, flags);
- for (;;) {
+ do {
long dirty_limit;
/* update interval */
- if (interval) {
- set_task_state(pupdated, TASK_INTERRUPTIBLE);
- schedule_timeout(interval);
- }
- if (signal_pending(pupdated))
- {
- int stopped = 0;
- spin_lock_irq(&pupdated->sigmask_lock);
- if (sigismember(&pupdated->pending.signal, SIGTERM))
- {
- sigdelset(&pupdated->pending.signal, SIGTERM);
- stopped = 1;
- }
- recalc_sigpending(pupdated);
- spin_unlock_irq(&pupdated->sigmask_lock);
- if (stopped) {
- printk("pupdated stopped...\n");
- set_task_state(pupdated, TASK_STOPPED);
- pupdated = NULL;
- return 0;
- }
+ if (pupdated.active == 1 && interval) {
+ mod_timer(&pupdated.timer, jiffies + interval);
+ interruptible_sleep_on(&pupdated.waitq);
}
+ if (pupdated.active == 0) {
+ del_timer(&pupdated.timer);
+ /* If stopped, we flush one last time... */
+ }
+
/* asynchronous setattr etc for the future ...
- obdfs_flush_dirty_inodes(jiffies - pupd_prm.age_super);
+ obdfs_flush_dirty_inodes(jiffies - pupdated.parms.age_super);
*/
- dirty_limit = nr_free_buffer_pages() * pupd_prm.nfract / 100;
+ dirty_limit = nr_free_buffer_pages() * pupdated.parms.nfract / 100;
if (obdfs_cache_count > dirty_limit) {
interval = 0;
- if ( wrote < pupd_prm.ndirty )
+ if (wrote < pupdated.parms.ndirty)
age >>= 1;
if (wrote)
CDEBUG(D_CACHE, "wrote %d, age %ld, interval %d\n",
wrote, age, interval);
} else {
- if ( wrote < pupd_prm.ndirty >> 1 &&
- obdfs_cache_count < dirty_limit / 2) {
- interval = pupd_prm.interval;
- age = pupd_prm.age_buffer;
+ if (wrote < pupdated.parms.ndirty >> 1 &&
+ obdfs_cache_count < dirty_limit / 2) {
+ interval = pupdated.parms.interval;
+ age = pupdated.parms.age_buffer;
if (wrote)
CDEBUG(D_INFO,
"wrote %d, age %ld, interval %d\n",
wrote, age, interval);
} else if (obdfs_cache_count > dirty_limit / 2) {
interval >>= 1;
- if ( wrote < pupd_prm.ndirty )
+ if (wrote < pupdated.parms.ndirty)
age >>= 1;
if (wrote)
CDEBUG(D_CACHE,
}
wrote = obdfs_flush_dirty_pages(jiffies - age);
- if (wrote)
+ if (wrote) {
CDEBUG(D_CACHE,
"dirty_limit %ld, cache_count %ld, wrote %d\n",
dirty_limit, obdfs_cache_count, wrote);
- }
+ run_task_queue(&tq_disk);
+ }
+ } while (pupdated.active == 1);
+
+ CDEBUG(D_CACHE, "pupdated stopped...\n");
+ pupdated.active = -1;
+ wake_up_interruptible (&pupdated.waitq);
+ return 0;
}
kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
*/
kernel_thread(pupdate, NULL, 0);
- CDEBUG(D_PSDEV, __FUNCTION__ ": flushd inited\n");
+ CDEBUG(D_PSDEV, "flushd inited\n");
return 0;
}
{
ENTRY;
- if (pupdated) /* for debugging purposes only */
- CDEBUG(D_CACHE, "pupdated->state = %lx\n", pupdated->state);
-
- /* deliver a signal to pupdated to shut it down */
- if (pupdated && (pupdated->state == TASK_RUNNING ||
- pupdated->state == TASK_INTERRUPTIBLE )) {
- unsigned long timeout = HZ/20;
- unsigned long count = 0;
- send_sig_info(SIGTERM, (struct siginfo *)1, pupdated);
- while (pupdated) {
- if ((count % 2*HZ) == timeout)
- printk(KERN_INFO "wait for pupdated to stop\n");
- count += timeout;
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(timeout);
- }
- }
+ /* Shut down pupdated. */
+ if (pupdated.active > 0) {
+ CDEBUG(D_CACHE, "inform pupdated\n");
+ pupdated.active = 0;
+ wake_up_interruptible(&pupdated.waitq);
+
+ CDEBUG(D_CACHE, "wait for pupdated\n");
+ while (pupdated.active == 0) {
+ interruptible_sleep_on(&pupdated.waitq);
+ }
+ CDEBUG(D_CACHE, "done waiting for pupdated\n");
+ }
EXIT;
- /* not reached */
return 0;
-
}