These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / include / linux / writeback.h
index b2dd371..d0b5ca5 100644 (file)
@@ -7,6 +7,8 @@
 #include <linux/sched.h>
 #include <linux/workqueue.h>
 #include <linux/fs.h>
+#include <linux/flex_proportions.h>
+#include <linux/backing-dev-defs.h>
 
 DECLARE_PER_CPU(int, dirty_throttle_leaks);
 
@@ -84,8 +86,85 @@ struct writeback_control {
        unsigned for_reclaim:1;         /* Invoked from the page allocator */
        unsigned range_cyclic:1;        /* range_start is cyclic */
        unsigned for_sync:1;            /* sync(2) WB_SYNC_ALL writeback */
+#ifdef CONFIG_CGROUP_WRITEBACK
+       struct bdi_writeback *wb;       /* wb this writeback is issued under */
+       struct inode *inode;            /* inode being written out */
+
+       /* foreign inode detection, see wbc_detach_inode() */
+       int wb_id;                      /* current wb id */
+       int wb_lcand_id;                /* last foreign candidate wb id */
+       int wb_tcand_id;                /* this foreign candidate wb id */
+       size_t wb_bytes;                /* bytes written by current wb */
+       size_t wb_lcand_bytes;          /* bytes written by last candidate */
+       size_t wb_tcand_bytes;          /* bytes written by this candidate */
+#endif
+};
+
+/*
+ * A wb_domain represents a domain that wb's (bdi_writeback's) belong to
+ * and are measured against each other in.  There always is one global
+ * domain, global_wb_domain, that every wb in the system is a member of.
+ * This allows measuring the relative bandwidth of each wb to distribute
+ * dirtyable memory accordingly.
+ */
+struct wb_domain {
+       spinlock_t lock;
+
+       /*
+        * Scale the writeback cache size proportional to the relative
+        * writeout speed.
+        *
+        * We do this by keeping a floating proportion between BDIs, based
+        * on page writeback completions [end_page_writeback()]. Those
+        * devices that write out pages fastest will get the larger share,
+        * while the slower will get a smaller share.
+        *
+        * We use page writeout completions because we are interested in
+        * getting rid of dirty pages. Having them written out is the
+        * primary goal.
+        *
+        * We introduce a concept of time, a period over which we measure
+        * these events, because demand can/will vary over time. The length
+        * of this period itself is measured in page writeback completions.
+        */
+       struct fprop_global completions;
+       struct timer_list period_timer; /* timer for aging of completions */
+       unsigned long period_time;
+
+       /*
+        * The dirtyable memory and dirty threshold could be suddenly
+        * knocked down by a large amount (eg. on the startup of KVM in a
+        * swapless system). This may throw the system into deep dirty
+        * exceeded state and throttle heavy/light dirtiers alike. To
+        * retain good responsiveness, maintain global_dirty_limit for
+        * tracking slowly down to the knocked down dirty threshold.
+        *
+        * Both fields are protected by ->lock.
+        */
+       unsigned long dirty_limit_tstamp;
+       unsigned long dirty_limit;
 };
 
+/**
+ * wb_domain_size_changed - memory available to a wb_domain has changed
+ * @dom: wb_domain of interest
+ *
+ * This function should be called when the amount of memory available to
+ * @dom has changed.  It resets @dom's dirty limit parameters to prevent
+ * the past values which don't match the current configuration from skewing
+ * dirty throttling.  Without this, when memory size of a wb_domain is
+ * greatly reduced, the dirty throttling logic may allow too many pages to
+ * be dirtied leading to consecutive unnecessary OOMs and may get stuck in
+ * that situation.
+ */
+static inline void wb_domain_size_changed(struct wb_domain *dom)
+{
+       spin_lock(&dom->lock);
+       dom->dirty_limit_tstamp = jiffies;
+       dom->dirty_limit = 0;
+       spin_unlock(&dom->lock);
+}
+
 /*
  * fs/fs-writeback.c
  */    
@@ -93,9 +172,9 @@ struct bdi_writeback;
 void writeback_inodes_sb(struct super_block *, enum wb_reason reason);
 void writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
                                                        enum wb_reason reason);
-int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
-int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
-                                 enum wb_reason reason);
+bool try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
+bool try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
+                                  enum wb_reason reason);
 void sync_inodes_sb(struct super_block *);
 void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
 void inode_wait_for_writeback(struct inode *inode);
@@ -107,6 +186,128 @@ static inline void wait_on_inode(struct inode *inode)
        wait_on_bit(&inode->i_state, __I_NEW, TASK_UNINTERRUPTIBLE);
 }
 
+#ifdef CONFIG_CGROUP_WRITEBACK
+
+#include <linux/cgroup.h>
+#include <linux/bio.h>
+
+void __inode_attach_wb(struct inode *inode, struct page *page);
+void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
+                                struct inode *inode)
+       __releases(&inode->i_lock);
+void wbc_detach_inode(struct writeback_control *wbc);
+void wbc_account_io(struct writeback_control *wbc, struct page *page,
+                   size_t bytes);
+void cgroup_writeback_umount(void);
+
+/**
+ * inode_attach_wb - associate an inode with its wb
+ * @inode: inode of interest
+ * @page: page being dirtied (may be NULL)
+ *
+ * If @inode doesn't have its wb, associate it with the wb matching the
+ * memcg of @page or, if @page is NULL, %current.  May be called w/ or w/o
+ * @inode->i_lock.
+ */
+static inline void inode_attach_wb(struct inode *inode, struct page *page)
+{
+       if (!inode->i_wb)
+               __inode_attach_wb(inode, page);
+}
+
+/**
+ * inode_detach_wb - disassociate an inode from its wb
+ * @inode: inode of interest
+ *
+ * @inode is being freed.  Detach from its wb.
+ */
+static inline void inode_detach_wb(struct inode *inode)
+{
+       if (inode->i_wb) {
+               wb_put(inode->i_wb);
+               inode->i_wb = NULL;
+       }
+}
+
+/**
+ * wbc_attach_fdatawrite_inode - associate wbc and inode for fdatawrite
+ * @wbc: writeback_control of interest
+ * @inode: target inode
+ *
+ * This function is to be used by __filemap_fdatawrite_range(), which is an
+ * alternative entry point into writeback code, and first ensures @inode is
+ * associated with a bdi_writeback and attaches it to @wbc.
+ */
+static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc,
+                                              struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       inode_attach_wb(inode, NULL);
+       wbc_attach_and_unlock_inode(wbc, inode);
+}
+
+/**
+ * wbc_init_bio - writeback specific initializtion of bio
+ * @wbc: writeback_control for the writeback in progress
+ * @bio: bio to be initialized
+ *
+ * @bio is a part of the writeback in progress controlled by @wbc.  Perform
+ * writeback specific initialization.  This is used to apply the cgroup
+ * writeback context.
+ */
+static inline void wbc_init_bio(struct writeback_control *wbc, struct bio *bio)
+{
+       /*
+        * pageout() path doesn't attach @wbc to the inode being written
+        * out.  This is intentional as we don't want the function to block
+        * behind a slow cgroup.  Ultimately, we want pageout() to kick off
+        * regular writeback instead of writing things out itself.
+        */
+       if (wbc->wb)
+               bio_associate_blkcg(bio, wbc->wb->blkcg_css);
+}
+
+#else  /* CONFIG_CGROUP_WRITEBACK */
+
+static inline void inode_attach_wb(struct inode *inode, struct page *page)
+{
+}
+
+static inline void inode_detach_wb(struct inode *inode)
+{
+}
+
+static inline void wbc_attach_and_unlock_inode(struct writeback_control *wbc,
+                                              struct inode *inode)
+       __releases(&inode->i_lock)
+{
+       spin_unlock(&inode->i_lock);
+}
+
+static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc,
+                                              struct inode *inode)
+{
+}
+
+static inline void wbc_detach_inode(struct writeback_control *wbc)
+{
+}
+
+static inline void wbc_init_bio(struct writeback_control *wbc, struct bio *bio)
+{
+}
+
+static inline void wbc_account_io(struct writeback_control *wbc,
+                                 struct page *page, size_t bytes)
+{
+}
+
+static inline void cgroup_writeback_umount(void)
+{
+}
+
+#endif /* CONFIG_CGROUP_WRITEBACK */
+
 /*
  * mm/page-writeback.c
  */
@@ -120,8 +321,12 @@ static inline void laptop_sync_completion(void) { }
 #endif
 void throttle_vm_writeout(gfp_t gfp_mask);
 bool zone_dirty_ok(struct zone *zone);
+int wb_domain_init(struct wb_domain *dom, gfp_t gfp);
+#ifdef CONFIG_CGROUP_WRITEBACK
+void wb_domain_exit(struct wb_domain *dom);
+#endif
 
-extern unsigned long global_dirty_limit;
+extern struct wb_domain global_wb_domain;
 
 /* These are exported to sysctl. */
 extern int dirty_background_ratio;
@@ -155,19 +360,12 @@ int dirty_writeback_centisecs_handler(struct ctl_table *, int,
                                      void __user *, size_t *, loff_t *);
 
 void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty);
-unsigned long bdi_dirty_limit(struct backing_dev_info *bdi,
-                              unsigned long dirty);
-
-void __bdi_update_bandwidth(struct backing_dev_info *bdi,
-                           unsigned long thresh,
-                           unsigned long bg_thresh,
-                           unsigned long dirty,
-                           unsigned long bdi_thresh,
-                           unsigned long bdi_dirty,
-                           unsigned long start_time);
+unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh);
 
+void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time);
 void page_writeback_init(void);
 void balance_dirty_pages_ratelimited(struct address_space *mapping);
+bool wb_over_bg_thresh(struct bdi_writeback *wb);
 
 typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
                                void *data);