diff options
author | Vivek Goyal <vgoyal@redhat.com> | 2020-08-19 18:19:48 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2020-09-10 11:39:22 +0200 |
commit | 45f2348eceb6a2a5b248ef44ea7dc2c4ede88b30 (patch) | |
tree | 14bc2d6cc9d135b190e3450aa0edd28367ad3f80 | |
parent | 1dd539577c42b67da796e2e758e04171bb889779 (diff) |
virtiofs: keep a list of free dax memory ranges
Divide the dax memory range into fixed size ranges (2MB for now) and put
them in a list. This will track free ranges. Once an inode requires a
free range, we will take one from here and put it in interval-tree
of ranges assigned to inode.
Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r-- | fs/fuse/dax.c | 91 |
1 files changed, 90 insertions, 1 deletions
diff --git a/fs/fuse/dax.c b/fs/fuse/dax.c index 9660d01f49a5..031106020f75 100644 --- a/fs/fuse/dax.c +++ b/fs/fuse/dax.c @@ -7,20 +7,104 @@ #include "fuse_i.h" #include <linux/dax.h> +#include <linux/pfn_t.h> + +/* Default memory range size, 2MB */ +#define FUSE_DAX_SHIFT 21 +#define FUSE_DAX_SZ (1 << FUSE_DAX_SHIFT) +#define FUSE_DAX_PAGES (FUSE_DAX_SZ / PAGE_SIZE) + +/** Translation information for file offsets to DAX window offsets */ +struct fuse_dax_mapping { + /* Will connect in fcd->free_ranges to keep track of free memory */ + struct list_head list; + + /** Position in DAX window */ + u64 window_offset; + + /** Length of mapping, in bytes */ + loff_t length; +}; struct fuse_conn_dax { /* DAX device */ struct dax_device *dev; + + /* DAX Window Free Ranges */ + long nr_free_ranges; + struct list_head free_ranges; }; +static void fuse_free_dax_mem_ranges(struct list_head *mem_list) +{ + struct fuse_dax_mapping *range, *temp; + + /* Free All allocated elements */ + list_for_each_entry_safe(range, temp, mem_list, list) { + list_del(&range->list); + kfree(range); + } +} + void fuse_dax_conn_free(struct fuse_conn *fc) { - kfree(fc->dax); + if (fc->dax) { + fuse_free_dax_mem_ranges(&fc->dax->free_ranges); + kfree(fc->dax); + } +} + +static int fuse_dax_mem_range_init(struct fuse_conn_dax *fcd) +{ + long nr_pages, nr_ranges; + void *kaddr; + pfn_t pfn; + struct fuse_dax_mapping *range; + int ret, id; + size_t dax_size = -1; + unsigned long i; + + INIT_LIST_HEAD(&fcd->free_ranges); + id = dax_read_lock(); + nr_pages = dax_direct_access(fcd->dev, 0, PHYS_PFN(dax_size), &kaddr, + &pfn); + dax_read_unlock(id); + if (nr_pages < 0) { + pr_debug("dax_direct_access() returned %ld\n", nr_pages); + return nr_pages; + } + + nr_ranges = nr_pages/FUSE_DAX_PAGES; + pr_debug("%s: dax mapped %ld pages. nr_ranges=%ld\n", + __func__, nr_pages, nr_ranges); + + for (i = 0; i < nr_ranges; i++) { + range = kzalloc(sizeof(struct fuse_dax_mapping), GFP_KERNEL); + ret = -ENOMEM; + if (!range) + goto out_err; + + /* TODO: This offset only works if virtio-fs driver is not + * having some memory hidden at the beginning. This needs + * better handling + */ + range->window_offset = i * FUSE_DAX_SZ; + range->length = FUSE_DAX_SZ; + list_add_tail(&range->list, &fcd->free_ranges); + } + + fcd->nr_free_ranges = nr_ranges; + return 0; +out_err: + /* Free All allocated elements */ + fuse_free_dax_mem_ranges(&fcd->free_ranges); + return ret; } int fuse_dax_conn_alloc(struct fuse_conn *fc, struct dax_device *dax_dev) { struct fuse_conn_dax *fcd; + int err; if (!dax_dev) return 0; @@ -30,6 +114,11 @@ int fuse_dax_conn_alloc(struct fuse_conn *fc, struct dax_device *dax_dev) return -ENOMEM; fcd->dev = dax_dev; + err = fuse_dax_mem_range_init(fcd); + if (err) { + kfree(fcd); + return err; + } fc->dax = fcd; return 0; |