[RFC 15/32] mars: add new module lib_mapfree
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
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) +