ANDROID: Incremental fs: fix .blocks_written
.blocks_writen file handling was missing some operations: SELinux xattr handlers, safety checks for it being a pseudo file etc. This CL generalizes pseudo file handling so that all such files work in a generic way and next time it should be easier to add all operations at once. Bug: 175823975 Test: incfs_tests pass Change-Id: Id2b1936018c81c62c8ab4cdbaa8827e2679b513f Signed-off-by: Yurii Zubrytskyi <zyy@google.com> Signed-off-by: Paul Lawrence <paullawrence@google.com>
This commit is contained in:
committed by
Alistair Delva
parent
43edfc892e
commit
b79605a904
@@ -123,6 +123,7 @@ int incfs_realloc_mount_info(struct mount_info *mi,
|
||||
|
||||
void incfs_free_mount_info(struct mount_info *mi)
|
||||
{
|
||||
int i;
|
||||
if (!mi)
|
||||
return;
|
||||
|
||||
@@ -136,8 +137,8 @@ void incfs_free_mount_info(struct mount_info *mi)
|
||||
mutex_destroy(&mi->mi_zstd_workspace_mutex);
|
||||
put_cred(mi->mi_owner);
|
||||
kfree(mi->mi_log.rl_ring_buf);
|
||||
kfree(mi->log_xattr);
|
||||
kfree(mi->pending_read_xattr);
|
||||
for (i = 0; i < ARRAY_SIZE(mi->pseudo_file_xattr); ++i)
|
||||
kfree(mi->pseudo_file_xattr[i].data);
|
||||
kfree(mi->mi_per_uid_read_timeouts);
|
||||
kfree(mi);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <uapi/linux/incrementalfs.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "pseudo_files.h"
|
||||
|
||||
#define SEGMENTS_PER_FILE 3
|
||||
|
||||
@@ -151,11 +152,8 @@ struct mount_info {
|
||||
/* Temporary buffer for read logger. */
|
||||
struct read_log mi_log;
|
||||
|
||||
void *log_xattr;
|
||||
size_t log_xattr_size;
|
||||
|
||||
void *pending_read_xattr;
|
||||
size_t pending_read_xattr_size;
|
||||
/* SELinux needs special xattrs on our pseudo files */
|
||||
struct mem_range pseudo_file_xattr[PSEUDO_FILE_COUNT];
|
||||
|
||||
/* A queue of waiters who want to be notified about blocks_written */
|
||||
wait_queue_head_t mi_blocks_written_notif_wq;
|
||||
|
||||
+182
-198
@@ -18,149 +18,15 @@
|
||||
#include "integrity.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#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 const struct mem_range log_file_name_range = {
|
||||
.data = (u8 *)log_file_name,
|
||||
.len = ARRAY_SIZE(log_file_name) - 1
|
||||
};
|
||||
|
||||
/* State of an open .log file, unique for each file descriptor. */
|
||||
struct log_file_state {
|
||||
struct read_log_state state;
|
||||
};
|
||||
|
||||
static ssize_t log_read(struct file *f, char __user *buf, size_t len,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct log_file_state *log_state = f->private_data;
|
||||
struct mount_info *mi = get_mount_info(file_superblock(f));
|
||||
int total_reads_collected = 0;
|
||||
int rl_size;
|
||||
ssize_t result = 0;
|
||||
bool report_uid;
|
||||
unsigned long page = 0;
|
||||
struct incfs_pending_read_info *reads_buf = NULL;
|
||||
struct incfs_pending_read_info2 *reads_buf2 = NULL;
|
||||
size_t record_size;
|
||||
ssize_t reads_to_collect;
|
||||
ssize_t reads_per_page;
|
||||
|
||||
if (!mi)
|
||||
return -EFAULT;
|
||||
|
||||
report_uid = mi->mi_options.report_uid;
|
||||
record_size = report_uid ? sizeof(*reads_buf2) : sizeof(*reads_buf);
|
||||
reads_to_collect = len / record_size;
|
||||
reads_per_page = PAGE_SIZE / record_size;
|
||||
|
||||
rl_size = READ_ONCE(mi->mi_log.rl_size);
|
||||
if (rl_size == 0)
|
||||
return 0;
|
||||
|
||||
page = __get_free_page(GFP_NOFS);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
if (report_uid)
|
||||
reads_buf2 = (struct incfs_pending_read_info2 *) page;
|
||||
else
|
||||
reads_buf = (struct incfs_pending_read_info *) page;
|
||||
|
||||
reads_to_collect = min_t(ssize_t, rl_size, reads_to_collect);
|
||||
while (reads_to_collect > 0) {
|
||||
struct read_log_state next_state;
|
||||
int reads_collected;
|
||||
|
||||
memcpy(&next_state, &log_state->state, sizeof(next_state));
|
||||
reads_collected = incfs_collect_logged_reads(
|
||||
mi, &next_state, reads_buf, reads_buf2,
|
||||
min_t(ssize_t, reads_to_collect, reads_per_page));
|
||||
if (reads_collected <= 0) {
|
||||
result = total_reads_collected ?
|
||||
total_reads_collected * record_size :
|
||||
reads_collected;
|
||||
goto out;
|
||||
}
|
||||
if (copy_to_user(buf, (void *) page,
|
||||
reads_collected * record_size)) {
|
||||
result = total_reads_collected ?
|
||||
total_reads_collected * record_size :
|
||||
-EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&log_state->state, &next_state, sizeof(next_state));
|
||||
total_reads_collected += reads_collected;
|
||||
buf += reads_collected * record_size;
|
||||
reads_to_collect -= reads_collected;
|
||||
}
|
||||
|
||||
result = total_reads_collected * record_size;
|
||||
*ppos = 0;
|
||||
out:
|
||||
free_page(page);
|
||||
return result;
|
||||
}
|
||||
|
||||
static __poll_t log_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct log_file_state *log_state = file->private_data;
|
||||
struct mount_info *mi = get_mount_info(file_superblock(file));
|
||||
int count;
|
||||
__poll_t ret = 0;
|
||||
|
||||
poll_wait(file, &mi->mi_log.ml_notif_wq, wait);
|
||||
count = incfs_get_uncollected_logs_count(mi, &log_state->state);
|
||||
if (count >= mi->mi_options.read_log_wakeup_count)
|
||||
ret = EPOLLIN | EPOLLRDNORM;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int log_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct log_file_state *log_state = NULL;
|
||||
struct mount_info *mi = get_mount_info(file_superblock(file));
|
||||
|
||||
log_state = kzalloc(sizeof(*log_state), GFP_NOFS);
|
||||
if (!log_state)
|
||||
return -ENOMEM;
|
||||
|
||||
log_state->state = incfs_get_log_state(mi);
|
||||
file->private_data = log_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
kfree(file->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations incfs_log_file_ops = {
|
||||
.read = log_read,
|
||||
.poll = log_poll,
|
||||
.open = log_open,
|
||||
.release = log_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
static bool is_pseudo_filename(struct mem_range name);
|
||||
|
||||
/*******************************************************************************
|
||||
* .pending_reads pseudo file definition
|
||||
******************************************************************************/
|
||||
#define INCFS_PENDING_READS_INODE 2
|
||||
static const char pending_reads_file_name[] = INCFS_PENDING_READS_FILENAME;
|
||||
static const struct mem_range pending_reads_file_name_range = {
|
||||
.data = (u8 *)pending_reads_file_name,
|
||||
.len = ARRAY_SIZE(pending_reads_file_name) - 1
|
||||
};
|
||||
|
||||
/* State of an open .pending_reads file, unique for each file descriptor. */
|
||||
struct pending_reads_state {
|
||||
@@ -343,16 +209,6 @@ static bool incfs_equal_ranges(struct mem_range lhs, struct mem_range rhs)
|
||||
return memcmp(lhs.data, rhs.data, lhs.len) == 0;
|
||||
}
|
||||
|
||||
static bool is_pseudo_filename(struct mem_range name)
|
||||
{
|
||||
if (incfs_equal_ranges(pending_reads_file_name_range, name))
|
||||
return true;
|
||||
if (incfs_equal_ranges(log_file_name_range, name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int validate_name(char *file_name)
|
||||
{
|
||||
struct mem_range name = range(file_name, strlen(file_name));
|
||||
@@ -1058,7 +914,7 @@ static long pending_reads_dispatch_ioctl(struct file *f, unsigned int req,
|
||||
}
|
||||
}
|
||||
|
||||
static const struct file_operations incfs_pending_read_file_ops = {
|
||||
static const struct file_operations incfs_pending_reads_file_ops = {
|
||||
.read = pending_reads_read,
|
||||
.poll = pending_reads_poll,
|
||||
.open = pending_reads_open,
|
||||
@@ -1068,14 +924,138 @@ static const struct file_operations incfs_pending_read_file_ops = {
|
||||
.compat_ioctl = pending_reads_dispatch_ioctl
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* .log pseudo file definition
|
||||
******************************************************************************/
|
||||
#define INCFS_LOG_INODE 3
|
||||
static const char log_file_name[] = INCFS_LOG_FILENAME;
|
||||
|
||||
/* State of an open .log file, unique for each file descriptor. */
|
||||
struct log_file_state {
|
||||
struct read_log_state state;
|
||||
};
|
||||
|
||||
static ssize_t log_read(struct file *f, char __user *buf, size_t len,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct log_file_state *log_state = f->private_data;
|
||||
struct mount_info *mi = get_mount_info(file_superblock(f));
|
||||
int total_reads_collected = 0;
|
||||
int rl_size;
|
||||
ssize_t result = 0;
|
||||
bool report_uid;
|
||||
unsigned long page = 0;
|
||||
struct incfs_pending_read_info *reads_buf = NULL;
|
||||
struct incfs_pending_read_info2 *reads_buf2 = NULL;
|
||||
size_t record_size;
|
||||
ssize_t reads_to_collect;
|
||||
ssize_t reads_per_page;
|
||||
|
||||
if (!mi)
|
||||
return -EFAULT;
|
||||
|
||||
report_uid = mi->mi_options.report_uid;
|
||||
record_size = report_uid ? sizeof(*reads_buf2) : sizeof(*reads_buf);
|
||||
reads_to_collect = len / record_size;
|
||||
reads_per_page = PAGE_SIZE / record_size;
|
||||
|
||||
rl_size = READ_ONCE(mi->mi_log.rl_size);
|
||||
if (rl_size == 0)
|
||||
return 0;
|
||||
|
||||
page = __get_free_page(GFP_NOFS);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
if (report_uid)
|
||||
reads_buf2 = (struct incfs_pending_read_info2 *)page;
|
||||
else
|
||||
reads_buf = (struct incfs_pending_read_info *)page;
|
||||
|
||||
reads_to_collect = min_t(ssize_t, rl_size, reads_to_collect);
|
||||
while (reads_to_collect > 0) {
|
||||
struct read_log_state next_state;
|
||||
int reads_collected;
|
||||
|
||||
memcpy(&next_state, &log_state->state, sizeof(next_state));
|
||||
reads_collected = incfs_collect_logged_reads(
|
||||
mi, &next_state, reads_buf, reads_buf2,
|
||||
min_t(ssize_t, reads_to_collect, reads_per_page));
|
||||
if (reads_collected <= 0) {
|
||||
result = total_reads_collected ?
|
||||
total_reads_collected * record_size :
|
||||
reads_collected;
|
||||
goto out;
|
||||
}
|
||||
if (copy_to_user(buf, (void *)page,
|
||||
reads_collected * record_size)) {
|
||||
result = total_reads_collected ?
|
||||
total_reads_collected * record_size :
|
||||
-EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&log_state->state, &next_state, sizeof(next_state));
|
||||
total_reads_collected += reads_collected;
|
||||
buf += reads_collected * record_size;
|
||||
reads_to_collect -= reads_collected;
|
||||
}
|
||||
|
||||
result = total_reads_collected * record_size;
|
||||
*ppos = 0;
|
||||
out:
|
||||
free_page(page);
|
||||
return result;
|
||||
}
|
||||
|
||||
static __poll_t log_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct log_file_state *log_state = file->private_data;
|
||||
struct mount_info *mi = get_mount_info(file_superblock(file));
|
||||
int count;
|
||||
__poll_t ret = 0;
|
||||
|
||||
poll_wait(file, &mi->mi_log.ml_notif_wq, wait);
|
||||
count = incfs_get_uncollected_logs_count(mi, &log_state->state);
|
||||
if (count >= mi->mi_options.read_log_wakeup_count)
|
||||
ret = EPOLLIN | EPOLLRDNORM;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int log_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct log_file_state *log_state = NULL;
|
||||
struct mount_info *mi = get_mount_info(file_superblock(file));
|
||||
|
||||
log_state = kzalloc(sizeof(*log_state), GFP_NOFS);
|
||||
if (!log_state)
|
||||
return -ENOMEM;
|
||||
|
||||
log_state->state = incfs_get_log_state(mi);
|
||||
file->private_data = log_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int log_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
kfree(file->private_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations incfs_log_file_ops = {
|
||||
.read = log_read,
|
||||
.poll = log_poll,
|
||||
.open = log_open,
|
||||
.release = log_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* .blocks_written pseudo file definition
|
||||
******************************************************************************/
|
||||
#define INCFS_BLOCKS_WRITTEN_INODE 4
|
||||
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 {
|
||||
@@ -1155,8 +1135,44 @@ static const struct file_operations incfs_blocks_written_file_ops = {
|
||||
/*******************************************************************************
|
||||
* Generic inode lookup functionality
|
||||
******************************************************************************/
|
||||
|
||||
const struct mem_range incfs_pseudo_file_names[] = {
|
||||
{ .data = (u8 *)pending_reads_file_name,
|
||||
.len = ARRAY_SIZE(pending_reads_file_name) - 1 },
|
||||
{ .data = (u8 *)log_file_name, .len = ARRAY_SIZE(log_file_name) - 1 },
|
||||
{ .data = (u8 *)blocks_written_file_name,
|
||||
.len = ARRAY_SIZE(blocks_written_file_name) - 1 }
|
||||
};
|
||||
|
||||
const unsigned long incfs_pseudo_file_inodes[] = { INCFS_PENDING_READS_INODE,
|
||||
INCFS_LOG_INODE,
|
||||
INCFS_BLOCKS_WRITTEN_INODE };
|
||||
|
||||
static const struct file_operations *const pseudo_file_operations[] = {
|
||||
&incfs_pending_reads_file_ops, &incfs_log_file_ops,
|
||||
&incfs_blocks_written_file_ops
|
||||
};
|
||||
|
||||
static bool is_pseudo_filename(struct mem_range name)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (; i < ARRAY_SIZE(incfs_pseudo_file_names); ++i)
|
||||
if (incfs_equal_ranges(incfs_pseudo_file_names[i], name))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool get_pseudo_inode(int ino, struct inode *inode)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (; i < ARRAY_SIZE(incfs_pseudo_file_inodes); ++i)
|
||||
if (ino == incfs_pseudo_file_inodes[i])
|
||||
break;
|
||||
if (i == ARRAY_SIZE(incfs_pseudo_file_inodes))
|
||||
return false;
|
||||
|
||||
inode->i_ctime = (struct timespec64){};
|
||||
inode->i_mtime = inode->i_ctime;
|
||||
inode->i_atime = inode->i_ctime;
|
||||
@@ -1165,23 +1181,8 @@ static bool get_pseudo_inode(int ino, struct inode *inode)
|
||||
inode->i_private = NULL;
|
||||
inode_init_owner(inode, NULL, S_IFREG | READ_WRITE_FILE_MODE);
|
||||
inode->i_op = &incfs_file_inode_ops;
|
||||
|
||||
switch (ino) {
|
||||
case INCFS_PENDING_READS_INODE:
|
||||
inode->i_fop = &incfs_pending_read_file_ops;
|
||||
return true;
|
||||
|
||||
case INCFS_LOG_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;
|
||||
}
|
||||
inode->i_fop = pseudo_file_operations[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
struct inode_search {
|
||||
@@ -1229,16 +1230,16 @@ int dir_lookup_pseudo_files(struct super_block *sb, struct dentry *dentry)
|
||||
range((u8 *)dentry->d_name.name, dentry->d_name.len);
|
||||
unsigned long ino;
|
||||
struct inode *inode;
|
||||
int i = 0;
|
||||
|
||||
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
|
||||
for (; i < ARRAY_SIZE(incfs_pseudo_file_names); ++i)
|
||||
if (incfs_equal_ranges(incfs_pseudo_file_names[i], name_range))
|
||||
break;
|
||||
if (i == ARRAY_SIZE(incfs_pseudo_file_names))
|
||||
return -ENOENT;
|
||||
|
||||
ino = incfs_pseudo_file_inodes[i];
|
||||
|
||||
inode = fetch_inode(sb, ino);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
@@ -1249,32 +1250,15 @@ int dir_lookup_pseudo_files(struct super_block *sb, struct dentry *dentry)
|
||||
|
||||
int emit_pseudo_files(struct dir_context *ctx)
|
||||
{
|
||||
if (ctx->pos == 0) {
|
||||
if (!dir_emit(ctx, pending_reads_file_name,
|
||||
ARRAY_SIZE(pending_reads_file_name) - 1,
|
||||
INCFS_PENDING_READS_INODE, DT_REG))
|
||||
loff_t i = ctx->pos;
|
||||
|
||||
for (; i < ARRAY_SIZE(incfs_pseudo_file_names); ++i) {
|
||||
if (!dir_emit(ctx, incfs_pseudo_file_names[i].data,
|
||||
incfs_pseudo_file_names[i].len,
|
||||
incfs_pseudo_file_inodes[i], DT_REG))
|
||||
return -EINVAL;
|
||||
|
||||
ctx->pos++;
|
||||
}
|
||||
|
||||
if (ctx->pos == 1) {
|
||||
if (!dir_emit(ctx, log_file_name,
|
||||
ARRAY_SIZE(log_file_name) - 1,
|
||||
INCFS_LOG_INODE, DT_REG))
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -6,9 +6,14 @@
|
||||
#ifndef _INCFS_PSEUDO_FILES_H
|
||||
#define _INCFS_PSEUDO_FILES_H
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
#define PSEUDO_FILE_COUNT 3
|
||||
#define INCFS_START_INO_RANGE 10
|
||||
|
||||
extern const struct mem_range incfs_pseudo_file_names[PSEUDO_FILE_COUNT];
|
||||
extern const unsigned long incfs_pseudo_file_inodes[PSEUDO_FILE_COUNT];
|
||||
|
||||
int dir_lookup_pseudo_files(struct super_block *sb, struct dentry *dentry);
|
||||
int emit_pseudo_files(struct dir_context *ctx);
|
||||
|
||||
|
||||
+15
-18
@@ -1434,6 +1434,7 @@ static ssize_t incfs_getxattr(struct dentry *d, const char *name,
|
||||
struct mount_info *mi = get_mount_info(d->d_sb);
|
||||
char *stored_value;
|
||||
size_t stored_size;
|
||||
int i;
|
||||
|
||||
if (di && di->backing_path.dentry)
|
||||
return vfs_getxattr(di->backing_path.dentry, name, value, size);
|
||||
@@ -1441,16 +1442,14 @@ static ssize_t incfs_getxattr(struct dentry *d, const char *name,
|
||||
if (strcmp(name, "security.selinux"))
|
||||
return -ENODATA;
|
||||
|
||||
if (!strcmp(d->d_iname, INCFS_PENDING_READS_FILENAME)) {
|
||||
stored_value = mi->pending_read_xattr;
|
||||
stored_size = mi->pending_read_xattr_size;
|
||||
} else if (!strcmp(d->d_iname, INCFS_LOG_FILENAME)) {
|
||||
stored_value = mi->log_xattr;
|
||||
stored_size = mi->log_xattr_size;
|
||||
} else {
|
||||
for (i = 0; i < PSEUDO_FILE_COUNT; ++i)
|
||||
if (!strcmp(d->d_iname, incfs_pseudo_file_names[i].data))
|
||||
break;
|
||||
if (i == PSEUDO_FILE_COUNT)
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
stored_value = mi->pseudo_file_xattr[i].data;
|
||||
stored_size = mi->pseudo_file_xattr[i].len;
|
||||
if (!stored_value)
|
||||
return -ENODATA;
|
||||
|
||||
@@ -1459,7 +1458,6 @@ static ssize_t incfs_getxattr(struct dentry *d, const char *name,
|
||||
|
||||
memcpy(value, stored_value, stored_size);
|
||||
return stored_size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1468,8 +1466,9 @@ static ssize_t incfs_setxattr(struct dentry *d, const char *name,
|
||||
{
|
||||
struct dentry_info *di = get_incfs_dentry(d);
|
||||
struct mount_info *mi = get_mount_info(d->d_sb);
|
||||
void **stored_value;
|
||||
u8 **stored_value;
|
||||
size_t *stored_size;
|
||||
int i;
|
||||
|
||||
if (di && di->backing_path.dentry)
|
||||
return vfs_setxattr(di->backing_path.dentry, name, value, size,
|
||||
@@ -1481,16 +1480,14 @@ static ssize_t incfs_setxattr(struct dentry *d, const char *name,
|
||||
if (size > INCFS_MAX_FILE_ATTR_SIZE)
|
||||
return -E2BIG;
|
||||
|
||||
if (!strcmp(d->d_iname, INCFS_PENDING_READS_FILENAME)) {
|
||||
stored_value = &mi->pending_read_xattr;
|
||||
stored_size = &mi->pending_read_xattr_size;
|
||||
} else if (!strcmp(d->d_iname, INCFS_LOG_FILENAME)) {
|
||||
stored_value = &mi->log_xattr;
|
||||
stored_size = &mi->log_xattr_size;
|
||||
} else {
|
||||
for (i = 0; i < PSEUDO_FILE_COUNT; ++i)
|
||||
if (!strcmp(d->d_iname, incfs_pseudo_file_names[i].data))
|
||||
break;
|
||||
if (i == PSEUDO_FILE_COUNT)
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
stored_value = &mi->pseudo_file_xattr[i].data;
|
||||
stored_size = &mi->pseudo_file_xattr[i].len;
|
||||
kfree (*stored_value);
|
||||
*stored_value = kzalloc(size, GFP_NOFS);
|
||||
if (!*stored_value)
|
||||
|
||||
Reference in New Issue
Block a user