diff options
author | Nicholas D Steeves <nsteeves@gmail.com> | 2016-04-23 00:41:30 +0100 |
---|---|---|
committer | Nicholas D Steeves <nsteeves@gmail.com> | 2016-04-23 00:41:30 +0100 |
commit | cec572daccafa1e912cbed363df6f84687778c6f (patch) | |
tree | 7d99ab9f73d25c1ed8eaf6393f6374edf5316b03 /file.c |
btrfs-progs (4.4.1-1.1) unstable; urgency=medium
* Non-maintainer upload.
* New upstream release.
* Rename package to btrfs-progs (Closes: #780081)
* Update standards version to 3.9.7 (no changes needed).
* debian/control: Add "Breaks" per Gianfranco Costamagna's suggestion
* Change lintian override to reflect package rename
* Switch from using postinst and postrm to using triggers
per Christian Seiler's recommendation.
# imported from the archive
Diffstat (limited to 'file.c')
-rw-r--r-- | file.c | 162 |
1 files changed, 162 insertions, 0 deletions
@@ -0,0 +1,162 @@ +/* + * Copyright (C) 2014 Fujitsu. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <sys/stat.h> +#include "ctree.h" +#include "transaction.h" +#include "kerncompat.h" + +/* + * Get the first file extent that covers (part of) the given range + * Unlike kernel using extent_map to handle hole even no-hole is enabled, + * progs don't have such infrastructure, so caller should do extra care + * for no-hole. + * + * return 0 for found, and path points to the file extent. + * return >0 for not found, and path points to the insert position. + * return <0 for error. + */ +int btrfs_get_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + u64 ino, u64 offset, u64 len, int ins_len) +{ + struct btrfs_key key; + struct btrfs_key found_key; + struct btrfs_file_extent_item *fi_item; + u64 end = 0; + int ret = 0; + int not_found = 1; + + key.objectid = ino; + key.type = BTRFS_EXTENT_DATA_KEY; + key.offset = offset; + + ret = btrfs_search_slot(trans, root, &key, path, ins_len, + ins_len ? 1 : 0); + if (ret <= 0) + goto out; + if (ret > 0) { + /* Check preivous file extent */ + ret = btrfs_previous_item(root, path, ino, + BTRFS_EXTENT_DATA_KEY); + if (ret < 0) + goto out; + if (ret > 0) + goto check_next; + } + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); + if (found_key.objectid != ino || + found_key.type != BTRFS_EXTENT_DATA_KEY) + goto check_next; + + fi_item = btrfs_item_ptr(path->nodes[0], path->slots[0], + struct btrfs_file_extent_item); + end = found_key.offset + + btrfs_file_extent_ram_bytes(path->nodes[0], fi_item); + /* + * existing file extent + * |--------| |----| + * |-------| + * offset + len + * OR + * |---------------| + * |-------| + */ + if (end > offset) { + not_found = 0; + goto out; + } +check_next: + ret = btrfs_next_item(root, path); + if (ret) + goto out; + + btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); + if (found_key.objectid != ino || + found_key.type != BTRFS_EXTENT_DATA_KEY) { + ret = 1; + goto out; + } + if (found_key.offset < offset + len) + /* + * existing file extent + * |---| |------| + * |-------| + * offset + len + */ + not_found = 0; + else + /* + * existing file extent + * |----| |----| + * |----| + * offset + len + */ + not_found = 1; + + /* + * To keep the search hehavior consistent with search_slot(), + * we need to go back to the prev leaf's nritem slot if + * we are at the first slot of the leaf. + */ + if (path->slots[0] == 0) { + ret = btrfs_prev_leaf(root, path); + /* Not possible */ + if (ret) + goto out; + path->slots[0] = btrfs_header_nritems(path->nodes[0]); + } + +out: + if (ret == 0) + ret = not_found; + return ret; +} + +/* + * Punch hole ranged [offset,len) for the file given by ino and root. + * + * Unlink kernel punch_hole, which will not zero/free existing extent, + * instead it will return -EEXIST if there is any extents in the hole + * range. + */ +int btrfs_punch_hole(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + u64 ino, u64 offset, u64 len) +{ + struct btrfs_path *path; + int ret = 0; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ret = btrfs_get_extent(NULL, root, path, ino, offset, len, 0); + if (ret < 0) + goto out; + if (ret == 0) { + ret = -EEXIST; + goto out; + } + + ret = btrfs_insert_file_extent(trans, root, ino, offset, 0, 0, len); +out: + btrfs_free_path(path); + return ret; +} |