Whamcloud - gitweb
- remainder of rmdir changes
[fs/lustre-release.git] / lustre / obdfs / flushd.c
index b56cc8a..9ba45ee 100644 (file)
@@ -2,6 +2,9 @@
  * 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.
@@ -22,7 +25,8 @@
  */
 #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
@@ -34,7 +38,19 @@ struct {
         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,
@@ -144,6 +160,9 @@ void obdfs_dequeue_pages(struct inode *inode)
         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)
 {
@@ -180,7 +199,7 @@ 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.
@@ -310,7 +329,7 @@ int obdfs_flush_dirty_pages(unsigned long check_time)
         struct list_head *sl;
         int max = 0;
 
-        ENTRY;
+       /*        ENTRY; */
         sl = &obdfs_super_list;
         while ( (sl = sl->prev) != &obdfs_super_list ) {
                 struct obdfs_sb_info *sbi = 
@@ -323,96 +342,108 @@ int obdfs_flush_dirty_pages(unsigned long check_time)
 
                 max = ret > max ? ret : max;
         }
-        EXIT;
+        if (max) { EXIT; }
         return max;
 } /* 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(&current->sigmask_lock, flags);
+       flush_signals(current);
+        sigfillset(&current->blocked);
+        recalc_sigpending(current);
+        spin_unlock_irqrestore(&current->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;
-                        CDEBUG(D_CACHE, "wrote %d, age %ld, interval %d\n",
+                        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;
-                                CDEBUG(D_INFO,
+                        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;
-                                CDEBUG(D_CACHE,
+                                if (wrote) 
+                                 CDEBUG(D_CACHE,
                                        "wrote %d, age %ld, interval %d\n",
                                        wrote, age, interval);
                         }
                 }
 
                 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;
 }
 
 
@@ -422,7 +453,7 @@ int obdfs_flushd_init(void)
         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;
 }
 
@@ -430,26 +461,19 @@ int obdfs_flushd_cleanup(void)
 {
         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;
-
 }