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>
This commit is contained in:
parent
1dd539577c
commit
45f2348ece
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue