##__VA_ARGS__); \
})
+static inline struct buffer_desc *exfat_de_iter_get_buffer(
+ struct exfat_de_iter *iter, unsigned int block)
+{
+ return &iter->buffer_desc[block % iter->exfat->buffer_count];
+}
+
static ssize_t write_block(struct exfat_de_iter *iter, unsigned int block)
{
off_t device_offset;
struct buffer_desc *desc;
unsigned int i;
- desc = &iter->buffer_desc[block & 0x01];
+ desc = exfat_de_iter_get_buffer(iter, block);
for (i = 0; i < iter->read_size / iter->write_size; i++) {
- if (desc->dirty[i]) {
+ if (BITMAP_GET(desc->dirty, i)) {
device_offset = exfat_c2o(exfat, desc->p_clus) +
desc->offset;
if (exfat_write(exfat->blk_dev->dev_fd,
device_offset + i * iter->write_size)
!= (ssize_t)iter->write_size)
return -EIO;
- desc->dirty[i] = 0;
+ BITMAP_CLEAR(desc->dirty, i);
}
}
return 0;
off_t device_offset;
ssize_t ret;
- desc = &iter->buffer_desc[block & 0x01];
+ desc = exfat_de_iter_get_buffer(iter, block);
if (block == 0) {
desc->p_clus = iter->parent->first_clus;
desc->offset = 0;
if (block > iter->parent->size / iter->read_size)
return EOF;
- prev_desc = &iter->buffer_desc[(block-1) & 0x01];
+ prev_desc = exfat_de_iter_get_buffer(iter, block - 1);
if (prev_desc->offset + 2 * iter->read_size <=
exfat->clus_size) {
desc->p_clus = prev_desc->p_clus;
iter->exfat = exfat;
iter->parent = dir;
iter->write_size = exfat->sect_size;
- iter->read_size = exfat->clus_size <= 4*KB ? exfat->clus_size : 4*KB;
+ iter->read_size = exfat_get_read_size(exfat);
if (exfat->clus_size <= 32 * KB)
iter->ra_partial_size = MAX(4 * KB, exfat->clus_size / 2);
else
off_t next_de_file_offset;
ssize_t ret;
unsigned int block;
+ struct buffer_desc *bd;
next_de_file_offset = iter->de_file_offset +
ith * sizeof(struct exfat_dentry);
if (next_de_file_offset + sizeof(struct exfat_dentry) >
iter->parent->size)
return EOF;
- /* the dentry must be in current, or next block which will be read */
- if (block > iter->de_file_offset / iter->read_size + 1)
- return -ERANGE;
/* read next cluster if needed */
if (next_de_file_offset >= iter->next_read_offset) {
if (ith + 1 > iter->max_skip_dentries)
iter->max_skip_dentries = ith + 1;
- *dentry = (struct exfat_dentry *)
- (iter->buffer_desc[block & 0x01].buffer +
+ bd = exfat_de_iter_get_buffer(iter, block);
+ *dentry = (struct exfat_dentry *)(bd->buffer +
next_de_file_offset % iter->read_size);
return 0;
}
off_t next_file_offset;
unsigned int block;
int ret, sect_idx;
+ struct buffer_desc *bd;
ret = exfat_de_iter_get(iter, ith, dentry);
if (!ret) {
block = (unsigned int)(next_file_offset / iter->read_size);
sect_idx = (int)((next_file_offset % iter->read_size) /
iter->write_size);
- iter->buffer_desc[block & 0x01].dirty[sect_idx] = 1;
+ bd = exfat_de_iter_get_buffer(iter, block);
+ BITMAP_SET(bd->dirty, sect_idx);
}
return ret;
int exfat_de_iter_flush(struct exfat_de_iter *iter)
{
- if (write_block(iter, 0) || write_block(iter, 1))
- return -EIO;
+ unsigned int i;
+
+ for (i = 0; i < iter->exfat->buffer_count; i++)
+ if (write_block(iter, i))
+ return -EIO;
return 0;
}
return EOF;
block = iter->de_file_offset / iter->read_size;
- bd = &iter->buffer_desc[block & 0x01];
+ bd = exfat_de_iter_get_buffer(iter, block);
return exfat_c2o(iter->exfat, bd->p_clus) + bd->offset +
iter->de_file_offset % iter->read_size;
}
int dentry_count, empty_dentry_count = 0;
int retval;
- bd = exfat_alloc_buffer(2, exfat->clus_size, exfat->sect_size);
- if (!bd)
- return -ENOMEM;
+ if (!exfat->lookup_buffer) {
+ exfat->lookup_buffer = exfat_alloc_buffer(exfat);
+ if (!exfat->lookup_buffer)
+ return -ENOMEM;
+ }
+ bd = exfat->lookup_buffer;
retval = exfat_de_iter_init(&de_iter, exfat, parent, bd);
if (retval == EOF || retval)
filter->out.file_offset = exfat_de_iter_file_offset(&de_iter);
filter->out.dev_offset = EOF;
}
- if (bd)
- exfat_free_buffer(bd, 2);
return retval;
}
for (i = 0; i < len; i++) {
ch = exfat->upcase_table[le16_to_cpu(name[i])];
- ch = cpu_to_le16(ch);
/* use += to avoid promotion to int; UBSan complaints about signed overflow */
chksum = (chksum << 15) | (chksum >> 1);
name_len = retval / 2;
dcount = 2 + DIV_ROUND_UP(name_len, ENTRY_NAME_MAX);
- dset = calloc(1, dcount * DENTRY_SIZE);
+ dset = calloc(dcount, DENTRY_SIZE);
if (!dset)
return -ENOMEM;
dset[1].dentry.stream.name_len = (__u8)name_len;
dset[1].dentry.stream.name_hash =
- exfat_calc_name_hash(exfat, utf16_name, name_len);
+ cpu_to_le16(exfat_calc_name_hash(exfat, utf16_name, name_len));
for (i = 2; i < dcount; i++) {
dset[i].type = EXFAT_NAME;
return 0;
}
-static int find_free_cluster(struct exfat *exfat,
- clus_t start, clus_t *new_clu)
+static int __find_free_cluster(struct exfat *exfat, clus_t *new_clu,
+ clus_t start, clus_t end)
{
- clus_t end = le32_to_cpu(exfat->bs->bsx.clu_count) +
- EXFAT_FIRST_CLUSTER;
-
- if (!exfat_heap_clus(exfat, start))
- return -EINVAL;
-
while (start < end) {
if (exfat_bitmap_find_zero(exfat, exfat->alloc_bitmap,
start, new_clu))
start = *new_clu + 1;
}
- end = start;
- start = EXFAT_FIRST_CLUSTER;
- while (start < end) {
- if (exfat_bitmap_find_zero(exfat, exfat->alloc_bitmap,
- start, new_clu))
- goto out_nospc;
- if (!exfat_bitmap_get(exfat->disk_bitmap, *new_clu))
- return 0;
- start = *new_clu + 1;
- }
-
-out_nospc:
*new_clu = EXFAT_EOF_CLUSTER;
+
return -ENOSPC;
}
+static int find_free_cluster(struct exfat *exfat,
+ clus_t start, clus_t *new_clu)
+{
+ clus_t end = le32_to_cpu(exfat->bs->bsx.clu_count) +
+ EXFAT_FIRST_CLUSTER;
+
+ if (!exfat_heap_clus(exfat, start))
+ return -EINVAL;
+
+ if (__find_free_cluster(exfat, new_clu, start, end) == 0)
+ return 0;
+
+ return __find_free_cluster(exfat, new_clu, EXFAT_FIRST_CLUSTER, start);
+}
+
+/* Find multiple contiguous free clusters */
+int exfat_find_free_cluster(struct exfat *exfat, int clu_count,
+ clus_t *new_clu)
+{
+ int ret, i;
+ clus_t clu;
+ clus_t start = EXFAT_FIRST_CLUSTER;
+ clus_t end = le32_to_cpu(exfat->bs->bsx.clu_count) +
+ EXFAT_FIRST_CLUSTER;
+
+find_again:
+ ret = __find_free_cluster(exfat, &clu, start, end);
+ if (ret < 0)
+ return ret;
+
+ *new_clu = clu;
+ start = clu + 1;
+
+ for (i = 1; i < clu_count && start < end; i++) {
+ ret = __find_free_cluster(exfat, &clu, start, end);
+ if (ret < 0)
+ return ret;
+
+ if (clu != start) {
+ start = clu;
+ goto find_again;
+ }
+
+ start = clu + 1;
+ }
+
+ if (start >= end)
+ return -ENOSPC;
+
+ return 0;
+}
+
static int exfat_map_cluster(struct exfat *exfat, struct exfat_inode *inode,
off_t file_off, clus_t *mapped_clu)
{
return 0;
}
-static int exfat_alloc_cluster(struct exfat *exfat, struct exfat_inode *inode,
- clus_t *new_clu)
+int exfat_alloc_cluster(struct exfat *exfat, struct exfat_inode *inode,
+ clus_t *new_clu)
{
clus_t last_clu;
int err;
return -EIO;
/* zero out the new cluster */
- if (exfat_write(exfat->blk_dev->dev_fd, exfat->zero_cluster,
- exfat->clus_size, exfat_c2o(exfat, *new_clu)) !=
- (ssize_t)exfat->clus_size) {
+ if (exfat_write_zero(exfat->blk_dev->dev_fd, exfat->clus_size,
+ exfat_c2o(exfat, *new_clu))) {
exfat_err("failed to fill new cluster with zeroes\n");
return -EIO;
}