Truncate data items

scoutfs_data_truncate_items() was still using the btree.  This updates
it to use the item cache but doesn't yet support regions being offline.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2017-04-18 13:44:54 -07:00
parent 92b10e8270
commit 429e1b6eb4
+34 -73
View File
@@ -25,7 +25,6 @@
#include "trans.h"
#include "counters.h"
#include "scoutfs_trace.h"
#include "btree.h"
#include "item.h"
#include "ioctl.h"
@@ -113,86 +112,59 @@ struct data_info {
#define BHA(bh) \
(bh), (u64)(bh)->b_blocknr, (bh)->b_size, (bh)->b_state \
static void init_data_key(struct scoutfs_key_buf *key,
struct scoutfs_data_key *dkey, u64 ino, u64 block)
{
dkey->type = SCOUTFS_DATA_KEY;
dkey->ino = cpu_to_be64(ino);
dkey->block = cpu_to_be64(block);
scoutfs_key_init(key, dkey, sizeof(struct scoutfs_data_key));
}
/*
* Free extents whose blocks fall inside the specified blocks. The
* caller holds a transaction.
*
* If 'release' is given then blocks are freed inside i_size but the
* extent items are left behind and their _OFFLINE flag is set.
* Delete the data block items in the given region.
*
* This is the low level extent item truncate code. Callers manage
* higher order truncation and orphan cleanup.
*
* XXX
* - restore support for releasing data.
* - for final unlink this would be better as a range deletion
* - probably don't want to read items to find them for removal
*/
int scoutfs_data_truncate_items(struct super_block *sb, u64 ino, u64 iblock,
u64 len, bool offline)
{
struct scoutfs_btree_root *meta = SCOUTFS_META(sb);
struct scoutfs_extent extent;
struct scoutfs_btree_val val;
struct scoutfs_key key;
struct scoutfs_key first;
u64 seq;
struct scoutfs_data_key last_dkey;
struct scoutfs_data_key dkey;
struct scoutfs_key_buf last;
struct scoutfs_key_buf key;
int ret;
/* XXX not yet updated */
trace_printk("iblock %llu len %llu offline %u\n",
iblock, len, offline);
scoutfs_set_key(&first, ino, SCOUTFS_EXTENT_KEY, iblock);
scoutfs_set_key(&key, ino, SCOUTFS_EXTENT_KEY, iblock + len - 1);
if (WARN_ON_ONCE(iblock + len <= iblock) ||
WARN_ON_ONCE(offline))
return -EINVAL;
trace_printk("iblock %llu\n", iblock);
scoutfs_btree_init_val(&val, &extent, sizeof(extent));
val.check_size_eq = 1;
init_data_key(&key, &dkey, ino, iblock);
init_data_key(&last, &last_dkey, ino, iblock + len - 1);
for (;;) {
ret = scoutfs_btree_prev(sb, meta, &first, &key, &key, &seq,
&val);
ret = scoutfs_item_next(sb, &key, &last, NULL);
if (ret < 0) {
if (ret == -ENOENT)
ret = 0;
break;
}
len = le64_to_cpu(extent.len);
if (WARN_ON_ONCE(len != 1)) {
ret = -EIO;
/* XXX would set offline bit items here */
ret = scoutfs_item_delete(sb, &key);
if (ret)
break;
}
/* XXX corruption: offline and allocation are exclusive */
if (!!extent.blkno ==
!!(extent.flags & SCOUTFS_EXTENT_FLAG_OFFLINE)) {
ret = -EIO;
break;
}
if (offline && (extent.flags & SCOUTFS_EXTENT_FLAG_OFFLINE))
continue;
/* make sure we can delete the extent after freeing */
if (extent.blkno) {
ret = scoutfs_btree_dirty(sb, meta, &key);
if (ret)
break;
ret = scoutfs_buddy_free(sb, cpu_to_le64(seq),
le64_to_cpu(extent.blkno), 0);
if (ret)
break;
}
if (offline) {
extent.blkno = 0;
extent.flags |= SCOUTFS_EXTENT_FLAG_OFFLINE;
scoutfs_btree_update(sb, meta, &key, &val);
} else {
ret = scoutfs_btree_delete(sb, meta, &key);
if (ret)
break;
}
/* XXX sync transaction if it's enormous */
scoutfs_dec_key(&key);
}
return ret;
@@ -248,24 +220,13 @@ void scoutfs_data_end_writeback(struct super_block *sb, int err)
}
}
static void init_data_key(struct scoutfs_key_buf *key,
struct scoutfs_data_key *dkey,
struct inode *inode, u64 block)
{
dkey->type = SCOUTFS_DATA_KEY;
dkey->ino = cpu_to_be64(scoutfs_ino(inode));
dkey->block = cpu_to_be64(block);
scoutfs_key_init(key, dkey, sizeof(struct scoutfs_data_key));
}
/* Iterate over all the data block items that make up the page. */
#define for_each_page_block(page, start, loff, block, key, dkey, val) \
for (start = 0; \
start < PAGE_CACHE_SIZE && \
(loff = ((loff_t)page->index << PAGE_CACHE_SHIFT) + start, \
block = loff >> SCOUTFS_BLOCK_SHIFT, \
init_data_key(&key, &dkey, page->mapping->host, block), \
init_data_key(&key, &dkey, \
scoutfs_ino(page->mapping->host), block), \
scoutfs_kvec_init(val, page_address(page) + start, \
SCOUTFS_BLOCK_SIZE), \
1); \