[RFC 15/32] mars: add new module lib_mapfree

2016-12-30 Thread Thomas Schoebel-Theuer
Signed-off-by: Thomas Schoebel-Theuer 
---
 drivers/staging/mars/xio_bricks/lib_mapfree.c | 382 ++
 include/linux/xio/lib_mapfree.h   |  84 ++
 2 files changed, 466 insertions(+)
 create mode 100644 drivers/staging/mars/xio_bricks/lib_mapfree.c
 create mode 100644 include/linux/xio/lib_mapfree.h

diff --git a/drivers/staging/mars/xio_bricks/lib_mapfree.c 
b/drivers/staging/mars/xio_bricks/lib_mapfree.c
new file mode 100644
index ..fc7c057fc993
--- /dev/null
+++ b/drivers/staging/mars/xio_bricks/lib_mapfree.c
@@ -0,0 +1,382 @@
+/*
+ * MARS Long Distance Replication Software
+ *
+ * Copyright (C) 2010-2014 Thomas Schoebel-Theuer
+ * Copyright (C) 2011-2014 1&1 Internet AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*  time to wait between background mapfree operations */
+int mapfree_period_sec = 10;
+
+/*  some grace space where no regular cleanup should occur */
+int mapfree_grace_keep_mb = 16;
+
+static
+DECLARE_RWSEM(mapfree_mutex);
+
+static
+LIST_HEAD(mapfree_list);
+
+void mapfree_pages(struct mapfree_info *mf, int grace_keep)
+{
+   struct address_space *mapping;
+   pgoff_t start;
+   pgoff_t end;
+
+   if (unlikely(!mf))
+   goto done;
+   if (unlikely(!mf->mf_filp))
+   goto done;
+
+   mapping = mf->mf_filp->f_mapping;
+   if (unlikely(!mapping))
+   goto done;
+
+   if (grace_keep < 0) { /*  force full flush */
+   start = 0;
+   end = -1;
+   } else {
+   unsigned long flags;
+   loff_t tmp;
+   loff_t min;
+
+   spin_lock_irqsave(>mf_lock, flags);
+
+   tmp = mf->mf_min[0];
+   min = tmp;
+   if (likely(mf->mf_min[1] < min))
+   min = mf->mf_min[1];
+   if (tmp) {
+   mf->mf_min[1] = tmp;
+   mf->mf_min[0] = 0;
+   }
+
+   spin_unlock_irqrestore(>mf_lock, flags);
+
+   min -= (loff_t)grace_keep * (1024 * 1024); /*  megabytes */
+   end = 0;
+
+   if (min > 0 || mf->mf_last) {
+   start = mf->mf_last / PAGE_SIZE;
+   /*  add some grace overlapping */
+   if (likely(start > 0))
+   start--;
+   mf->mf_last = min;
+   end = min / PAGE_SIZE;
+   } else  { /*  there was no progress for at least 2 rounds */
+   start = 0;
+   if (!grace_keep) /*  also flush thoroughly */
+   end = -1;
+   }
+
+   XIO_DBG("file = '%s' start = %lu end = %lu\n", mf->mf_name, 
start, end);
+   }
+
+   if (end > start || end == -1)
+   invalidate_mapping_pages(mapping, start, end);
+
+done:;
+}
+
+static
+void _mapfree_put(struct mapfree_info *mf)
+{
+   if (atomic_dec_and_test(>mf_count)) {
+   XIO_DBG("closing file '%s' filp = %p\n", mf->mf_name, 
mf->mf_filp);
+   list_del_init(>mf_head);
+   CHECK_HEAD_EMPTY(>mf_dirty_anchor);
+   if (likely(mf->mf_filp)) {
+   mapfree_pages(mf, -1);
+   filp_close(mf->mf_filp, NULL);
+   }
+   brick_string_free(mf->mf_name);
+   brick_mem_free(mf);
+   }
+}
+
+void mapfree_put(struct mapfree_info *mf)
+{
+   if (likely(mf)) {
+   down_write(_mutex);
+   _mapfree_put(mf);
+   up_write(_mutex);
+   }
+}
+
+struct mapfree_info *mapfree_get(const char *name, int flags)
+{
+   struct mapfree_info *mf = NULL;
+   struct list_head *tmp;
+
+   if (!(flags & O_DIRECT)) {
+   down_read(_mutex);
+   for (tmp = mapfree_list.next; tmp != _list; tmp = 
tmp->next) {
+   struct mapfree_info *_mf = container_of(tmp, struct 
mapfree_info, mf_head);
+
+   if (_mf->mf_flags == flags && !strcmp(_mf->mf_name, 
name)) {
+   mf = _mf;
+   atomic_inc(>mf_count);
+   break;
+   }
+   }
+   up_read(_mutex);
+
+   

[RFC 15/32] mars: add new module lib_mapfree

2016-12-30 Thread Thomas Schoebel-Theuer
Signed-off-by: Thomas Schoebel-Theuer 
---
 drivers/staging/mars/xio_bricks/lib_mapfree.c | 382 ++
 include/linux/xio/lib_mapfree.h   |  84 ++
 2 files changed, 466 insertions(+)
 create mode 100644 drivers/staging/mars/xio_bricks/lib_mapfree.c
 create mode 100644 include/linux/xio/lib_mapfree.h

diff --git a/drivers/staging/mars/xio_bricks/lib_mapfree.c 
b/drivers/staging/mars/xio_bricks/lib_mapfree.c
new file mode 100644
index ..fc7c057fc993
--- /dev/null
+++ b/drivers/staging/mars/xio_bricks/lib_mapfree.c
@@ -0,0 +1,382 @@
+/*
+ * MARS Long Distance Replication Software
+ *
+ * Copyright (C) 2010-2014 Thomas Schoebel-Theuer
+ * Copyright (C) 2011-2014 1&1 Internet AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*  time to wait between background mapfree operations */
+int mapfree_period_sec = 10;
+
+/*  some grace space where no regular cleanup should occur */
+int mapfree_grace_keep_mb = 16;
+
+static
+DECLARE_RWSEM(mapfree_mutex);
+
+static
+LIST_HEAD(mapfree_list);
+
+void mapfree_pages(struct mapfree_info *mf, int grace_keep)
+{
+   struct address_space *mapping;
+   pgoff_t start;
+   pgoff_t end;
+
+   if (unlikely(!mf))
+   goto done;
+   if (unlikely(!mf->mf_filp))
+   goto done;
+
+   mapping = mf->mf_filp->f_mapping;
+   if (unlikely(!mapping))
+   goto done;
+
+   if (grace_keep < 0) { /*  force full flush */
+   start = 0;
+   end = -1;
+   } else {
+   unsigned long flags;
+   loff_t tmp;
+   loff_t min;
+
+   spin_lock_irqsave(>mf_lock, flags);
+
+   tmp = mf->mf_min[0];
+   min = tmp;
+   if (likely(mf->mf_min[1] < min))
+   min = mf->mf_min[1];
+   if (tmp) {
+   mf->mf_min[1] = tmp;
+   mf->mf_min[0] = 0;
+   }
+
+   spin_unlock_irqrestore(>mf_lock, flags);
+
+   min -= (loff_t)grace_keep * (1024 * 1024); /*  megabytes */
+   end = 0;
+
+   if (min > 0 || mf->mf_last) {
+   start = mf->mf_last / PAGE_SIZE;
+   /*  add some grace overlapping */
+   if (likely(start > 0))
+   start--;
+   mf->mf_last = min;
+   end = min / PAGE_SIZE;
+   } else  { /*  there was no progress for at least 2 rounds */
+   start = 0;
+   if (!grace_keep) /*  also flush thoroughly */
+   end = -1;
+   }
+
+   XIO_DBG("file = '%s' start = %lu end = %lu\n", mf->mf_name, 
start, end);
+   }
+
+   if (end > start || end == -1)
+   invalidate_mapping_pages(mapping, start, end);
+
+done:;
+}
+
+static
+void _mapfree_put(struct mapfree_info *mf)
+{
+   if (atomic_dec_and_test(>mf_count)) {
+   XIO_DBG("closing file '%s' filp = %p\n", mf->mf_name, 
mf->mf_filp);
+   list_del_init(>mf_head);
+   CHECK_HEAD_EMPTY(>mf_dirty_anchor);
+   if (likely(mf->mf_filp)) {
+   mapfree_pages(mf, -1);
+   filp_close(mf->mf_filp, NULL);
+   }
+   brick_string_free(mf->mf_name);
+   brick_mem_free(mf);
+   }
+}
+
+void mapfree_put(struct mapfree_info *mf)
+{
+   if (likely(mf)) {
+   down_write(_mutex);
+   _mapfree_put(mf);
+   up_write(_mutex);
+   }
+}
+
+struct mapfree_info *mapfree_get(const char *name, int flags)
+{
+   struct mapfree_info *mf = NULL;
+   struct list_head *tmp;
+
+   if (!(flags & O_DIRECT)) {
+   down_read(_mutex);
+   for (tmp = mapfree_list.next; tmp != _list; tmp = 
tmp->next) {
+   struct mapfree_info *_mf = container_of(tmp, struct 
mapfree_info, mf_head);
+
+   if (_mf->mf_flags == flags && !strcmp(_mf->mf_name, 
name)) {
+   mf = _mf;
+   atomic_inc(>mf_count);
+   break;
+   }
+   }
+   up_read(_mutex);
+
+   if (mf)
+