ANDROID: Incremental fs: Add setattr call

As was, chmod would change the cached inode's mode, which would
persist until the inode was uncached.

Fix to change mode of backing file, but make sure mount files
are read only, backing files are always writeable.

Test: App no longer fails with incfs errors
Bug: 154972299
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Change-Id: I40517331f24329484387c6b880f1517f887b29f6
(cherry picked from commit fe4fae35fe307a15cacc5e6693a98bf5140e643b)
This commit is contained in:
Paul Lawrence 2020-04-29 08:00:18 -07:00 committed by Alistair Delva
parent cb3a87a370
commit c7c8c61370

View File

@ -68,6 +68,7 @@ static struct inode *alloc_inode(struct super_block *sb);
static void free_inode(struct inode *inode); static void free_inode(struct inode *inode);
static void evict_inode(struct inode *inode); static void evict_inode(struct inode *inode);
static int incfs_setattr(struct dentry *dentry, struct iattr *ia);
static ssize_t incfs_getxattr(struct dentry *d, const char *name, static ssize_t incfs_getxattr(struct dentry *d, const char *name,
void *value, size_t size); void *value, size_t size);
static ssize_t incfs_setxattr(struct dentry *d, const char *name, static ssize_t incfs_setxattr(struct dentry *d, const char *name,
@ -98,7 +99,8 @@ static const struct inode_operations incfs_dir_inode_ops = {
.rename = dir_rename_wrap, .rename = dir_rename_wrap,
.unlink = dir_unlink, .unlink = dir_unlink,
.link = dir_link, .link = dir_link,
.rmdir = dir_rmdir .rmdir = dir_rmdir,
.setattr = incfs_setattr,
}; };
static const struct file_operations incfs_dir_fops = { static const struct file_operations incfs_dir_fops = {
@ -158,7 +160,7 @@ static const struct file_operations incfs_log_file_ops = {
}; };
static const struct inode_operations incfs_file_inode_ops = { static const struct inode_operations incfs_file_inode_ops = {
.setattr = simple_setattr, .setattr = incfs_setattr,
.getattr = simple_getattr, .getattr = simple_getattr,
.listxattr = incfs_listxattr .listxattr = incfs_listxattr
}; };
@ -369,6 +371,7 @@ static int inode_set(struct inode *inode, void *opaque)
inode->i_mapping->a_ops = &incfs_address_space_ops; inode->i_mapping->a_ops = &incfs_address_space_ops;
inode->i_op = &incfs_file_inode_ops; inode->i_op = &incfs_file_inode_ops;
inode->i_fop = &incfs_file_ops; inode->i_fop = &incfs_file_ops;
inode->i_mode &= ~0222;
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
inode->i_size = 0; inode->i_size = 0;
inode->i_blocks = 1; inode->i_blocks = 1;
@ -2029,6 +2032,45 @@ static void evict_inode(struct inode *inode)
clear_inode(inode); clear_inode(inode);
} }
static int incfs_setattr(struct dentry *dentry, struct iattr *ia)
{
struct dentry_info *di = get_incfs_dentry(dentry);
struct dentry *backing_dentry;
struct inode *backing_inode;
int error;
if (ia->ia_valid & ATTR_SIZE)
return -EINVAL;
if (!di)
return -EINVAL;
backing_dentry = di->backing_path.dentry;
if (!backing_dentry)
return -EINVAL;
backing_inode = d_inode(backing_dentry);
/* incfs files are readonly, but the backing files must be writeable */
if (S_ISREG(backing_inode->i_mode)) {
if ((ia->ia_valid & ATTR_MODE) && (ia->ia_mode & 0222))
return -EINVAL;
ia->ia_mode |= 0222;
}
inode_lock(d_inode(backing_dentry));
error = notify_change(backing_dentry, ia, NULL);
inode_unlock(d_inode(backing_dentry));
if (error)
return error;
if (S_ISREG(backing_inode->i_mode))
ia->ia_mode &= ~0222;
return simple_setattr(dentry, ia);
}
static ssize_t incfs_getxattr(struct dentry *d, const char *name, static ssize_t incfs_getxattr(struct dentry *d, const char *name,
void *value, size_t size) void *value, size_t size)
{ {