Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/bio_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,15 @@ struct inode *page_get_inode(struct page *pg)
return pg->mapping->host;
}

int bio_needs_cow(struct bio *bio, struct inode *inode)
int bio_needs_cow(struct bio *bio, struct snap_device *dev)
{
bio_iter_t iter;
bio_iter_bvec_t bvec;

if (!test_bit(SD_FLAG_COW_RESIDENT, &dev->sd_flags)) {
return 1; // if the cow is non-resident, then we don't need to check if the bio is for the cow file.
}

#ifdef HAVE_ENUM_REQ_OPF
//#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
if (bio_op(bio) == REQ_OP_WRITE_ZEROES)
Expand All @@ -339,7 +343,7 @@ int bio_needs_cow(struct bio *bio, struct inode *inode)
// check the inode of each page return true if it does not match our cow
// file
bio_for_each_segment (bvec, bio, iter) {
if (page_get_inode(bio_iter_page(bio, iter)) != inode)
if (page_get_inode(bio_iter_page(bio, iter)) != dev->sd_cow_inode)
return 1;
}

Expand Down
2 changes: 1 addition & 1 deletion src/bio_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ void dattobd_bio_op_clear_flag(struct bio *bio, unsigned int flag);

struct inode *page_get_inode(struct page *pg);

int bio_needs_cow(struct bio *bio, struct inode *inode);
int bio_needs_cow(struct bio *bio, struct snap_device *dev);

void bio_free_clone(struct bio *bio);

Expand Down
5 changes: 4 additions & 1 deletion src/proc_seq_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ static int dattobd_proc_show(struct seq_file *m, void *v)
seq_printf(m, "\t\t\t\"minor\": %u,\n", dev->sd_minor);
seq_printf(m, "\t\t\t\"cow_file\": \"%s\",\n",
dev->sd_cow_path);
seq_printf(m, "\t\t\t\"full_cow_path\": \"%s\",\n",
dev->sd_cow_full_path);
seq_printf(m, "\t\t\t\"block_device\": \"%s\",\n",
dev->sd_bdev_path);
seq_printf(m, "\t\t\t\"max_cache\": %lu,\n",
Expand Down Expand Up @@ -133,7 +135,8 @@ static int dattobd_proc_show(struct seq_file *m, void *v)
if (error)
seq_printf(m, "\t\t\t\"error\": %d,\n", error);

seq_printf(m, "\t\t\t\"state\": %lu\n", dev->sd_state);
seq_printf(m, "\t\t\t\"state\": %lu,\n", dev->sd_state);
seq_printf(m, "\t\t\t\"resident\": %d\n", test_bit(SD_FLAG_COW_RESIDENT, &dev->sd_flags));
seq_printf(m, "\t\t}");
}

Expand Down
7 changes: 6 additions & 1 deletion src/snap_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@
#define ACTIVE 1
#define UNVERIFIED 2

// macros for defining the flags of a snap_device (bit offsets)
#define SD_FLAG_COW_RESIDENT 0 // the cow file exists on the backing device

struct snap_device {
unsigned int sd_minor; // minor number of the snapshot
unsigned long sd_state; // current state of the snapshot
unsigned long sd_flags; // flags
unsigned long sd_falloc_size; // space allocated to the cow file (in
// megabytes)
unsigned long sd_cache_size; // maximum cache size (in bytes)
Expand All @@ -31,7 +35,8 @@ struct snap_device {
struct block_device *sd_base_dev; // device being snapshot
char *sd_bdev_path; // base device file path
struct cow_manager *sd_cow; // cow manager
char *sd_cow_path; // cow file path
char *sd_cow_path; // cow file path (for resident cow files)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be marked as deprecated in a comment?

char *sd_cow_full_path; // full cow file path (for non-resident cow files)
struct inode *sd_cow_inode; // cow file inode
make_request_fn
*sd_orig_mrf; // block device's original make request function
Expand Down
13 changes: 4 additions & 9 deletions src/system_call_hooking.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,11 @@ int __handle_bdev_mount_nowrite(const struct vfsmount *mnt,
dev->sd_base_dev != mnt->mnt_sb->s_bdev)
continue;

// if we are unmounting the vfsmount we are using go to dormant
// state
if (mnt == dattobd_get_mnt(dev->sd_cow->filp)) {
LOG_DEBUG("block device umount detected for device %d",
i);
auto_transition_dormant(i);
LOG_DEBUG("block device umount detected for device %d", i);
auto_transition_dormant(i);

ret = 0;
goto out;
}
ret = 0;
goto out;
}
i = 0;
ret = -ENODEV;
Expand Down
44 changes: 30 additions & 14 deletions src/tracer.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ static int snap_trace_bio(struct snap_device *dev, struct bio *bio)
unsigned int bytes, pages;

// if we don't need to cow this bio just call the real mrf normally
if (!bio_needs_cow(bio, dev->sd_cow_inode))
if (!bio_needs_cow(bio, dev))
return dattobd_call_mrf(dev->sd_orig_mrf,
dattobd_bio_get_queue(bio), bio);

Expand Down Expand Up @@ -255,6 +255,14 @@ static int inc_trace_bio(struct snap_device *dev, struct bio *bio)
bio_iter_t iter;
bio_iter_bvec_t bvec;

if (!test_bit(SD_FLAG_COW_RESIDENT, &dev->sd_flags)) {
// if the cow is non-resident, then we don't need to check if
// the bio is for the cow file.
ret = inc_make_sset(dev, bio_sector(bio),
bio_size(bio) / SECTOR_SIZE);
goto out;
}

#ifdef HAVE_ENUM_REQ_OPF
//#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
if (bio_op(bio) == REQ_OP_WRITE_ZEROES) {
Expand Down Expand Up @@ -406,10 +414,7 @@ static int __tracer_destroy_cow(struct snap_device *dev, int close_method)
if (dev->sd_cow) {
LOG_DEBUG("destroying cow manager");

if (close_method == 0) {
cow_free(dev->sd_cow);
dev->sd_cow = NULL;
} else if (close_method == 1) {
if (close_method == 0 || close_method == 1) {
ret = cow_sync_and_free(dev->sd_cow);
dev->sd_cow = NULL;
} else if (close_method == 2) {
Expand Down Expand Up @@ -483,11 +488,8 @@ static int __tracer_setup_cow(struct snap_device *dev,
}
}

// verify that file is on block device
if (!file_is_on_bdev(dev->sd_cow->filp, bdev)) {
ret = -EINVAL;
LOG_ERROR(ret, "'%s' is not on '%s'", cow_path, bdev_name);
goto error;
if (file_is_on_bdev(dev->sd_cow->filp, bdev)) {
set_bit(SD_FLAG_COW_RESIDENT, &dev->sd_flags);
}

// find the cow file's inode number
Expand Down Expand Up @@ -627,6 +629,12 @@ static void __tracer_destroy_cow_path(struct snap_device *dev)
kfree(dev->sd_cow_path);
dev->sd_cow_path = NULL;
}

if (dev->sd_cow_full_path) {
LOG_DEBUG("freeing full cow path");
kfree(dev->sd_cow_full_path);
dev->sd_cow_full_path = NULL;
}
}

static int __tracer_setup_cow_path(struct snap_device *dev,
Expand All @@ -635,6 +643,11 @@ static int __tracer_setup_cow_path(struct snap_device *dev,
int ret;

// get the pathname of the cow file (relative to the mountpoint)
LOG_DEBUG("getting absolute pathname of cow file");
ret = file_get_absolute_pathname(cow_file, &dev->sd_cow_full_path, NULL);
if (ret)
goto error;

LOG_DEBUG("getting relative pathname of cow file");
ret = dentry_get_relative_pathname(dattobd_get_dentry(cow_file),
&dev->sd_cow_path, NULL);
Expand Down Expand Up @@ -1579,14 +1592,17 @@ void __tracer_dormant_to_active(struct snap_device *dev,
const char __user *user_mount_path)
{
int ret;
char *resident_cow_path;
char *cow_path;

// generate the full pathname
ret = user_mount_pathname_concat(user_mount_path, dev->sd_cow_path,
&cow_path);
&resident_cow_path);
if (ret)
goto error;

cow_path = test_bit(SD_FLAG_COW_RESIDENT, &dev->sd_flags) ? resident_cow_path : dev->sd_cow_full_path;

// setup the cow manager
ret = __tracer_setup_cow_reopen(dev, dev->sd_base_dev, cow_path);
if (ret)
Expand All @@ -1608,13 +1624,13 @@ void __tracer_dormant_to_active(struct snap_device *dev,
set_bit(ACTIVE, &dev->sd_state);
clear_bit(UNVERIFIED, &dev->sd_state);

kfree(cow_path);
kfree(resident_cow_path);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be freed immediately after __tracer_setup_cow_reopen() and then the extra test/free in the error: case could be removed?


return;

error:
LOG_ERROR(ret, "error transitioning tracer to active state");
if (cow_path)
kfree(cow_path);
if (resident_cow_path)
kfree(resident_cow_path);
tracer_set_fail_state(dev, ret);
}