ANDROID: Incremental fs: Add .blocks_written file

Bug: 162856396
Test: incfs_test passes
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: I942582218cdc7741bcff2f264960b76cdfa1bb36
This commit is contained in:
Paul Lawrence
2020-08-20 15:03:54 -07:00
parent 14bb6f87db
commit cb776f4576
8 changed files with 204 additions and 47 deletions

View File

@@ -43,6 +43,8 @@ struct mount_info *incfs_alloc_mount_info(struct super_block *sb,
mutex_init(&mi->mi_dir_struct_mutex);
init_waitqueue_head(&mi->mi_pending_reads_notif_wq);
init_waitqueue_head(&mi->mi_log.ml_notif_wq);
init_waitqueue_head(&mi->mi_blocks_written_notif_wq);
atomic_set(&mi->mi_blocks_written, 0);
INIT_DELAYED_WORK(&mi->mi_log.ml_wakeup_work, log_wake_up_all);
spin_lock_init(&mi->mi_log.rl_lock);
spin_lock_init(&mi->pending_read_lock);
@@ -902,6 +904,9 @@ static void notify_pending_reads(struct mount_info *mi,
}
rcu_read_unlock();
wake_up_all(&segment->new_data_arrival_wq);
atomic_inc(&mi->mi_blocks_written);
wake_up_all(&mi->mi_blocks_written_notif_wq);
}
static int wait_for_data_block(struct data_file *df, int block_index,

View File

@@ -155,6 +155,13 @@ struct mount_info {
void *pending_read_xattr;
size_t pending_read_xattr_size;
/* A queue of waiters who want to be notified about blocks_written */
wait_queue_head_t mi_blocks_written_notif_wq;
/* Number of blocks written since mount */
atomic_t mi_blocks_written;
};
struct data_file_block {

View File

@@ -20,13 +20,14 @@
#define INCFS_PENDING_READS_INODE 2
#define INCFS_LOG_INODE 3
#define INCFS_BLOCKS_WRITTEN_INODE 4
#define READ_WRITE_FILE_MODE 0666
/*******************************************************************************
* .log pseudo file definition
******************************************************************************/
static const char log_file_name[] = INCFS_LOG_FILENAME;
static struct mem_range log_file_name_range = {
static const struct mem_range log_file_name_range = {
.data = (u8 *)log_file_name,
.len = ARRAY_SIZE(log_file_name) - 1
};
@@ -156,7 +157,7 @@ static const struct file_operations incfs_log_file_ops = {
* .pending_reads pseudo file definition
******************************************************************************/
static const char pending_reads_file_name[] = INCFS_PENDING_READS_FILENAME;
static struct mem_range pending_reads_file_name_range = {
static const struct mem_range pending_reads_file_name_range = {
.data = (u8 *)pending_reads_file_name,
.len = ARRAY_SIZE(pending_reads_file_name) - 1
};
@@ -927,6 +928,90 @@ static const struct file_operations incfs_pending_read_file_ops = {
.compat_ioctl = pending_reads_dispatch_ioctl
};
/*******************************************************************************
* .blocks_written pseudo file definition
******************************************************************************/
static const char blocks_written_file_name[] = INCFS_BLOCKS_WRITTEN_FILENAME;
static const struct mem_range blocks_written_file_name_range = {
.data = (u8 *)blocks_written_file_name,
.len = ARRAY_SIZE(blocks_written_file_name) - 1
};
/* State of an open .blocks_written file, unique for each file descriptor. */
struct blocks_written_file_state {
unsigned long blocks_written;
};
static ssize_t blocks_written_read(struct file *f, char __user *buf, size_t len,
loff_t *ppos)
{
struct mount_info *mi = get_mount_info(file_superblock(f));
struct blocks_written_file_state *state = f->private_data;
unsigned long blocks_written;
char string[21];
int result = 0;
if (!mi)
return -EFAULT;
blocks_written = atomic_read(&mi->mi_blocks_written);
if (state->blocks_written == blocks_written)
return 0;
result = snprintf(string, sizeof(string), "%lu", blocks_written);
if (result > len)
result = len;
if (copy_to_user(buf, string, result))
return -EFAULT;
state->blocks_written = blocks_written;
return result;
}
static __poll_t blocks_written_poll(struct file *f, poll_table *wait)
{
struct mount_info *mi = get_mount_info(file_superblock(f));
struct blocks_written_file_state *state = f->private_data;
unsigned long blocks_written;
if (!mi)
return -EFAULT;
poll_wait(f, &mi->mi_blocks_written_notif_wq, wait);
blocks_written = atomic_read(&mi->mi_blocks_written);
if (state->blocks_written == blocks_written)
return 0;
return EPOLLIN | EPOLLRDNORM;
}
static int blocks_written_open(struct inode *inode, struct file *file)
{
struct blocks_written_file_state *state =
kzalloc(sizeof(*state), GFP_NOFS);
if (!state)
return -ENOMEM;
state->blocks_written = -1;
file->private_data = state;
return 0;
}
static int blocks_written_release(struct inode *inode, struct file *file)
{
kfree(file->private_data);
return 0;
}
static const struct file_operations incfs_blocks_written_file_ops = {
.read = blocks_written_read,
.poll = blocks_written_poll,
.open = blocks_written_open,
.release = blocks_written_release,
.llseek = noop_llseek,
};
/*******************************************************************************
* Generic inode lookup functionality
******************************************************************************/
@@ -950,6 +1035,10 @@ static bool get_pseudo_inode(int ino, struct inode *inode)
inode->i_fop = &incfs_log_file_ops;
return true;
case INCFS_BLOCKS_WRITTEN_INODE:
inode->i_fop = &incfs_blocks_written_file_ops;
return true;
default:
return false;
}
@@ -977,27 +1066,10 @@ static int inode_set(struct inode *inode, void *opaque)
return -EINVAL;
}
static struct inode *fetch_pending_reads_inode(struct super_block *sb)
static struct inode *fetch_inode(struct super_block *sb, unsigned long ino)
{
struct inode_search search = {
.ino = INCFS_PENDING_READS_INODE
};
struct inode *inode = iget5_locked(sb, search.ino, inode_test,
inode_set, &search);
if (!inode)
return ERR_PTR(-ENOMEM);
if (inode->i_state & I_NEW)
unlock_new_inode(inode);
return inode;
}
static struct inode *fetch_log_inode(struct super_block *sb)
{
struct inode_search search = {
.ino = INCFS_LOG_INODE
.ino = ino
};
struct inode *inode = iget5_locked(sb, search.ino, inode_test,
inode_set, &search);
@@ -1015,28 +1087,24 @@ int dir_lookup_pseudo_files(struct super_block *sb, struct dentry *dentry)
{
struct mem_range name_range =
range((u8 *)dentry->d_name.name, dentry->d_name.len);
unsigned long ino;
struct inode *inode;
if (incfs_equal_ranges(pending_reads_file_name_range, name_range)) {
struct inode *inode = fetch_pending_reads_inode(sb);
if (incfs_equal_ranges(pending_reads_file_name_range, name_range))
ino = INCFS_PENDING_READS_INODE;
else if (incfs_equal_ranges(log_file_name_range, name_range))
ino = INCFS_LOG_INODE;
else if (incfs_equal_ranges(blocks_written_file_name_range, name_range))
ino = INCFS_BLOCKS_WRITTEN_INODE;
else
return -ENOENT;
if (IS_ERR(inode))
return PTR_ERR(inode);
inode = fetch_inode(sb, ino);
if (IS_ERR(inode))
return PTR_ERR(inode);
d_add(dentry, inode);
return 0;
}
if (incfs_equal_ranges(log_file_name_range, name_range)) {
struct inode *inode = fetch_log_inode(sb);
if (IS_ERR(inode))
return PTR_ERR(inode);
d_add(dentry, inode);
return 0;
}
return -ENOENT;
d_add(dentry, inode);
return 0;
}
int emit_pseudo_files(struct dir_context *ctx)
@@ -1059,5 +1127,14 @@ int emit_pseudo_files(struct dir_context *ctx)
ctx->pos++;
}
if (ctx->pos == 2) {
if (!dir_emit(ctx, blocks_written_file_name,
ARRAY_SIZE(blocks_written_file_name) - 1,
INCFS_BLOCKS_WRITTEN_INODE, DT_REG))
return -EINVAL;
ctx->pos++;
}
return 0;
}

View File

@@ -6,7 +6,7 @@
#ifndef _INCFS_PSEUDO_FILES_H
#define _INCFS_PSEUDO_FILES_H
#define PSEUDO_FILE_COUNT 2
#define PSEUDO_FILE_COUNT 3
#define INCFS_START_INO_RANGE 10
int dir_lookup_pseudo_files(struct super_block *sb, struct dentry *dentry);

View File

@@ -30,6 +30,7 @@
#define INCFS_PENDING_READS_FILENAME ".pending_reads"
#define INCFS_LOG_FILENAME ".log"
#define INCFS_BLOCKS_WRITTEN_FILENAME ".blocks_written"
#define INCFS_XATTR_ID_NAME (XATTR_USER_PREFIX "incfs.id")
#define INCFS_XATTR_SIZE_NAME (XATTR_USER_PREFIX "incfs.size")
#define INCFS_XATTR_METADATA_NAME (XATTR_USER_PREFIX "incfs.metadata")

View File

@@ -7,6 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include <lz4.h>
#include <poll.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -963,6 +964,7 @@ static bool iterate_directory(const char *dir_to_iterate, bool root,
} names[] = {
{INCFS_LOG_FILENAME, true, false},
{INCFS_PENDING_READS_FILENAME, true, false},
{INCFS_BLOCKS_WRITTEN_FILENAME, true, false},
{".index", true, false},
{"..", false, false},
{".", false, false},
@@ -2293,10 +2295,39 @@ static int emit_partial_test_file_data(const char *mount_dir,
int *block_indexes = NULL;
int result = 0;
int blocks_written = 0;
int bw_fd = -1;
char buffer[20];
struct pollfd pollfd;
long blocks_written_total, blocks_written_new_total;
if (file->size == 0)
return 0;
bw_fd = open_blocks_written_file(mount_dir);
if (bw_fd == -1)
return -errno;
result = read(bw_fd, buffer, sizeof(buffer));
if (result <= 0) {
result = -EIO;
goto out;
}
buffer[result] = 0;
blocks_written_total = atol(buffer);
result = 0;
pollfd = (struct pollfd) {
.fd = bw_fd,
.events = POLLIN,
};
result = poll(&pollfd, 1, 0);
if (result) {
result = -EIO;
goto out;
}
/* Emit 2 blocks, skip 2 blocks etc*/
block_indexes = calloc(block_cnt, sizeof(*block_indexes));
for (i = 0, j = 0; i < block_cnt; ++i)
@@ -2316,9 +2347,29 @@ static int emit_partial_test_file_data(const char *mount_dir,
result = -EIO;
goto out;
}
result = poll(&pollfd, 1, 0);
if (result != 1 || pollfd.revents != POLLIN) {
result = -EIO;
goto out;
}
result = read(bw_fd, buffer, sizeof(buffer));
buffer[result] = 0;
blocks_written_new_total = atol(buffer);
if (blocks_written_new_total - blocks_written_total
!= blocks_written) {
result = -EIO;
goto out;
}
blocks_written_total = blocks_written_new_total;
result = 0;
}
out:
free(block_indexes);
close(bw_fd);
return result;
}

View File

@@ -234,14 +234,28 @@ int open_commands_file(const char *mount_dir)
int open_log_file(const char *mount_dir)
{
char cmd_file[255];
int cmd_fd;
char file[255];
int fd;
snprintf(cmd_file, ARRAY_SIZE(cmd_file), "%s/.log", mount_dir);
cmd_fd = open(cmd_file, O_RDWR | O_CLOEXEC);
if (cmd_fd < 0)
snprintf(file, ARRAY_SIZE(file), "%s/.log", mount_dir);
fd = open(file, O_RDWR | O_CLOEXEC);
if (fd < 0)
perror("Can't open log file");
return cmd_fd;
return fd;
}
int open_blocks_written_file(const char *mount_dir)
{
char file[255];
int fd;
snprintf(file, ARRAY_SIZE(file),
"%s/%s", mount_dir, INCFS_BLOCKS_WRITTEN_FILENAME);
fd = open(file, O_RDONLY | O_CLOEXEC);
if (fd < 0)
perror("Can't open blocks_written file");
return fd;
}
int wait_for_pending_reads(int fd, int timeout_ms,

View File

@@ -52,6 +52,8 @@ int open_commands_file(const char *mount_dir);
int open_log_file(const char *mount_dir);
int open_blocks_written_file(const char *mount_dir);
int wait_for_pending_reads(int fd, int timeout_ms,
struct incfs_pending_read_info *prs, int prs_count);