Commit 01504f5e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'upstream-4.4-rc1' of git://git.infradead.org/linux-ubifs

Pull UBI/UBIFS updates from Richard Weinberger:

 - access time support for UBIFS by Dongsheng Yang

 - random cleanups and bug fixes all over the place

* tag 'upstream-4.4-rc1' of git://git.infradead.org/linux-ubifs:
  ubifs: introduce UBIFS_ATIME_SUPPORT to ubifs
  ubifs: make ubifs_[get|set]xattr atomic
  UBIFS: Delete unnecessary checks before the function call "iput"
  UBI: Remove in vain semicolon
  UBI: Fastmap: Fix PEB array type
  UBIFS: Fix possible memory leak in ubifs_readdir()
  fs/ubifs: remove unnecessary new_valid_dev check
  ubi: fastmap: Implement produce_free_peb()
  UBIFS: print verbose message when rescanning a corrupted node
  UBIFS: call dbg_is_power_cut() instead of reading c->dbg->pc_happened
  UBI: drop null test before destroy functions
  UBI: Update comments to reflect UBI_METAONLY flag
  UBI: Fix debug message
  UBI: Fix typo in comment
  UBI: Fastmap: Simplify expression
  UBIFS: fix a typo in comment of ubifs_budget_req
  UBIFS: use kmemdup rather than duplicating its implementation
parents 4bde961e 8c1c5f26
...@@ -1209,9 +1209,7 @@ static void destroy_ai(struct ubi_attach_info *ai) ...@@ -1209,9 +1209,7 @@ static void destroy_ai(struct ubi_attach_info *ai)
} }
} }
if (ai->aeb_slab_cache) kmem_cache_destroy(ai->aeb_slab_cache);
kmem_cache_destroy(ai->aeb_slab_cache);
kfree(ai); kfree(ai);
} }
......
...@@ -949,7 +949,7 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd, ...@@ -949,7 +949,7 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
if (!req) { if (!req) {
err = -ENOMEM; err = -ENOMEM;
break; break;
}; }
err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req)); err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));
if (err) { if (err) {
......
...@@ -1358,7 +1358,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap, ...@@ -1358,7 +1358,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
continue; continue;
ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!", ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!",
vol->vol_id, i, fm_eba[i][j], vol->vol_id, j, fm_eba[i][j],
scan_eba[i][j]); scan_eba[i][j]);
ubi_assert(0); ubi_assert(0);
} }
......
...@@ -171,6 +171,30 @@ void ubi_refill_pools(struct ubi_device *ubi) ...@@ -171,6 +171,30 @@ void ubi_refill_pools(struct ubi_device *ubi)
spin_unlock(&ubi->wl_lock); spin_unlock(&ubi->wl_lock);
} }
/**
* produce_free_peb - produce a free physical eraseblock.
* @ubi: UBI device description object
*
* This function tries to make a free PEB by means of synchronous execution of
* pending works. This may be needed if, for example the background thread is
* disabled. Returns zero in case of success and a negative error code in case
* of failure.
*/
static int produce_free_peb(struct ubi_device *ubi)
{
int err;
while (!ubi->free.rb_node && ubi->works_count) {
dbg_wl("do one work synchronously");
err = do_work(ubi);
if (err)
return err;
}
return 0;
}
/** /**
* ubi_wl_get_peb - get a physical eraseblock. * ubi_wl_get_peb - get a physical eraseblock.
* @ubi: UBI device description object * @ubi: UBI device description object
...@@ -213,6 +237,11 @@ int ubi_wl_get_peb(struct ubi_device *ubi) ...@@ -213,6 +237,11 @@ int ubi_wl_get_peb(struct ubi_device *ubi)
} }
retried = 1; retried = 1;
up_read(&ubi->fm_eba_sem); up_read(&ubi->fm_eba_sem);
ret = produce_free_peb(ubi);
if (ret < 0) {
down_read(&ubi->fm_eba_sem);
goto out;
}
goto again; goto again;
} }
......
...@@ -450,7 +450,7 @@ static void unmap_peb(struct ubi_attach_info *ai, int pnum) ...@@ -450,7 +450,7 @@ static void unmap_peb(struct ubi_attach_info *ai, int pnum)
* < 0 indicates an internal error. * < 0 indicates an internal error.
*/ */
static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
int *pebs, int pool_size, unsigned long long *max_sqnum, __be32 *pebs, int pool_size, unsigned long long *max_sqnum,
struct list_head *free) struct list_head *free)
{ {
struct ubi_vid_hdr *vh; struct ubi_vid_hdr *vh;
...@@ -775,7 +775,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi, ...@@ -775,7 +775,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) { for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) {
int pnum = be32_to_cpu(fm_eba->pnum[j]); int pnum = be32_to_cpu(fm_eba->pnum[j]);
if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0) if (pnum < 0)
continue; continue;
aeb = NULL; aeb = NULL;
......
...@@ -500,7 +500,7 @@ struct ubi_fm_volhdr { ...@@ -500,7 +500,7 @@ struct ubi_fm_volhdr {
/* struct ubi_fm_volhdr is followed by one struct ubi_fm_eba records */ /* struct ubi_fm_volhdr is followed by one struct ubi_fm_eba records */
/** /**
* struct ubi_fm_eba - denotes an association beween a PEB and LEB * struct ubi_fm_eba - denotes an association between a PEB and LEB
* @magic: EBA table magic number * @magic: EBA table magic number
* @reserved_pebs: number of table entries * @reserved_pebs: number of table entries
* @pnum: PEB number of LEB (LEB is the index) * @pnum: PEB number of LEB (LEB is the index)
......
...@@ -35,3 +35,18 @@ config UBIFS_FS_ZLIB ...@@ -35,3 +35,18 @@ config UBIFS_FS_ZLIB
default y default y
help help
Zlib compresses better than LZO but it is slower. Say 'Y' if unsure. Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
config UBIFS_ATIME_SUPPORT
bool "Access time support" if UBIFS_FS
depends on UBIFS_FS
default n
help
Originally UBIFS did not support atime, because it looked like a bad idea due
increased flash wear. This option adds atime support and it is disabled by default
to preserve the old behavior. If you enable this option, UBIFS starts updating atime,
which means that file-system read operations will cause writes (inode atime
updates). This may affect file-system performance and increase flash device wear,
so be careful. How often atime is updated depends on the selected strategy:
strictatime is the "heavy", relatime is "lighter", etc.
If unsure, say 'N'
...@@ -2573,7 +2573,7 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, ...@@ -2573,7 +2573,7 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
{ {
int err, failing; int err, failing;
if (c->dbg->pc_happened) if (dbg_is_power_cut(c))
return -EROFS; return -EROFS;
failing = power_cut_emulated(c, lnum, 1); failing = power_cut_emulated(c, lnum, 1);
...@@ -2595,7 +2595,7 @@ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, ...@@ -2595,7 +2595,7 @@ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
{ {
int err; int err;
if (c->dbg->pc_happened) if (dbg_is_power_cut(c))
return -EROFS; return -EROFS;
if (power_cut_emulated(c, lnum, 1)) if (power_cut_emulated(c, lnum, 1))
return -EROFS; return -EROFS;
...@@ -2611,7 +2611,7 @@ int dbg_leb_unmap(struct ubifs_info *c, int lnum) ...@@ -2611,7 +2611,7 @@ int dbg_leb_unmap(struct ubifs_info *c, int lnum)
{ {
int err; int err;
if (c->dbg->pc_happened) if (dbg_is_power_cut(c))
return -EROFS; return -EROFS;
if (power_cut_emulated(c, lnum, 0)) if (power_cut_emulated(c, lnum, 0))
return -EROFS; return -EROFS;
...@@ -2627,7 +2627,7 @@ int dbg_leb_map(struct ubifs_info *c, int lnum) ...@@ -2627,7 +2627,7 @@ int dbg_leb_map(struct ubifs_info *c, int lnum)
{ {
int err; int err;
if (c->dbg->pc_happened) if (dbg_is_power_cut(c))
return -EROFS; return -EROFS;
if (power_cut_emulated(c, lnum, 0)) if (power_cut_emulated(c, lnum, 0))
return -EROFS; return -EROFS;
......
...@@ -449,13 +449,14 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx) ...@@ -449,13 +449,14 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
} }
out: out:
kfree(file->private_data);
file->private_data = NULL;
if (err != -ENOENT) { if (err != -ENOENT) {
ubifs_err(c, "cannot find next direntry, error %d", err); ubifs_err(c, "cannot find next direntry, error %d", err);
return err; return err;
} }
kfree(file->private_data);
file->private_data = NULL;
/* 2 is a special value indicating that there are no more direntries */ /* 2 is a special value indicating that there are no more direntries */
ctx->pos = 2; ctx->pos = 2;
return 0; return 0;
...@@ -787,9 +788,6 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry, ...@@ -787,9 +788,6 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino); dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino);
if (!new_valid_dev(rdev))
return -EINVAL;
if (S_ISBLK(mode) || S_ISCHR(mode)) { if (S_ISBLK(mode) || S_ISCHR(mode)) {
dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
if (!dev) if (!dev)
...@@ -1188,6 +1186,9 @@ const struct inode_operations ubifs_dir_inode_operations = { ...@@ -1188,6 +1186,9 @@ const struct inode_operations ubifs_dir_inode_operations = {
.getxattr = ubifs_getxattr, .getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr, .removexattr = ubifs_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time,
#endif
}; };
const struct file_operations ubifs_dir_operations = { const struct file_operations ubifs_dir_operations = {
......
...@@ -1354,6 +1354,47 @@ static inline int mctime_update_needed(const struct inode *inode, ...@@ -1354,6 +1354,47 @@ static inline int mctime_update_needed(const struct inode *inode,
return 0; return 0;
} }
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
/**
* ubifs_update_time - update time of inode.
* @inode: inode to update
*
* This function updates time of the inode.
*/
int ubifs_update_time(struct inode *inode, struct timespec *time,
int flags)
{
struct ubifs_inode *ui = ubifs_inode(inode);
struct ubifs_info *c = inode->i_sb->s_fs_info;
struct ubifs_budget_req req = { .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(ui->data_len, 8) };
int iflags = I_DIRTY_TIME;
int err, release;
err = ubifs_budget_space(c, &req);
if (err)
return err;
mutex_lock(&ui->ui_mutex);
if (flags & S_ATIME)
inode->i_atime = *time;
if (flags & S_CTIME)
inode->i_ctime = *time;
if (flags & S_MTIME)
inode->i_mtime = *time;
if (!(inode->i_sb->s_flags & MS_LAZYTIME))
iflags |= I_DIRTY_SYNC;
release = ui->dirty;
__mark_inode_dirty(inode, iflags);
mutex_unlock(&ui->ui_mutex);
if (release)
ubifs_release_budget(c, &req);
return 0;
}
#endif
/** /**
* update_ctime - update mtime and ctime of an inode. * update_ctime - update mtime and ctime of an inode.
* @inode: inode to update * @inode: inode to update
...@@ -1537,6 +1578,9 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -1537,6 +1578,9 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
if (err) if (err)
return err; return err;
vma->vm_ops = &ubifs_file_vm_ops; vma->vm_ops = &ubifs_file_vm_ops;
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
file_accessed(file);
#endif
return 0; return 0;
} }
...@@ -1557,6 +1601,9 @@ const struct inode_operations ubifs_file_inode_operations = { ...@@ -1557,6 +1601,9 @@ const struct inode_operations ubifs_file_inode_operations = {
.getxattr = ubifs_getxattr, .getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr, .removexattr = ubifs_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time,
#endif
}; };
const struct inode_operations ubifs_symlink_inode_operations = { const struct inode_operations ubifs_symlink_inode_operations = {
...@@ -1568,6 +1615,9 @@ const struct inode_operations ubifs_symlink_inode_operations = { ...@@ -1568,6 +1615,9 @@ const struct inode_operations ubifs_symlink_inode_operations = {
.getxattr = ubifs_getxattr, .getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr, .listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr, .removexattr = ubifs_removexattr,
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
.update_time = ubifs_update_time,
#endif
}; };
const struct file_operations ubifs_file_operations = { const struct file_operations ubifs_file_operations = {
......
...@@ -1498,11 +1498,10 @@ static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c, ...@@ -1498,11 +1498,10 @@ static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
} }
/* nnode is being committed, so copy it */ /* nnode is being committed, so copy it */
n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS); n = kmemdup(nnode, sizeof(struct ubifs_nnode), GFP_NOFS);
if (unlikely(!n)) if (unlikely(!n))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memcpy(n, nnode, sizeof(struct ubifs_nnode));
n->cnext = NULL; n->cnext = NULL;
__set_bit(DIRTY_CNODE, &n->flags); __set_bit(DIRTY_CNODE, &n->flags);
__clear_bit(COW_CNODE, &n->flags); __clear_bit(COW_CNODE, &n->flags);
...@@ -1549,11 +1548,10 @@ static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c, ...@@ -1549,11 +1548,10 @@ static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
} }
/* pnode is being committed, so copy it */ /* pnode is being committed, so copy it */
p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS); p = kmemdup(pnode, sizeof(struct ubifs_pnode), GFP_NOFS);
if (unlikely(!p)) if (unlikely(!p))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memcpy(p, pnode, sizeof(struct ubifs_pnode));
p->cnext = NULL; p->cnext = NULL;
__set_bit(DIRTY_CNODE, &p->flags); __set_bit(DIRTY_CNODE, &p->flags);
__clear_bit(COW_CNODE, &p->flags); __clear_bit(COW_CNODE, &p->flags);
......
...@@ -155,13 +155,8 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf) ...@@ -155,13 +155,8 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
*/ */
static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev) static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev)
{ {
if (new_valid_dev(rdev)) { dev->new = cpu_to_le32(new_encode_dev(rdev));
dev->new = cpu_to_le32(new_encode_dev(rdev)); return sizeof(dev->new);
return sizeof(dev->new);
} else {
dev->huge = cpu_to_le64(huge_encode_dev(rdev));
return sizeof(dev->huge);
}
} }
/** /**
......
...@@ -789,7 +789,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum, ...@@ -789,7 +789,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
corrupted_rescan: corrupted_rescan:
/* Re-scan the corrupted data with verbose messages */ /* Re-scan the corrupted data with verbose messages */
ubifs_err(c, "corruption %d", ret); ubifs_err(c, "corruption %d", ret);
ubifs_scan_a_node(c, buf, len, lnum, offs, 1); ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
corrupted: corrupted:
ubifs_scanned_corruption(c, lnum, offs, buf); ubifs_scanned_corruption(c, lnum, offs, buf);
err = -EUCLEAN; err = -EUCLEAN;
...@@ -1331,8 +1331,7 @@ void ubifs_destroy_size_tree(struct ubifs_info *c) ...@@ -1331,8 +1331,7 @@ void ubifs_destroy_size_tree(struct ubifs_info *c)
struct size_entry *e, *n; struct size_entry *e, *n;
rbtree_postorder_for_each_entry_safe(e, n, &c->size_tree, rb) { rbtree_postorder_for_each_entry_safe(e, n, &c->size_tree, rb) {
if (e->inode) iput(e->inode);
iput(e->inode);
kfree(e); kfree(e);
} }
...@@ -1533,8 +1532,7 @@ int ubifs_recover_size(struct ubifs_info *c) ...@@ -1533,8 +1532,7 @@ int ubifs_recover_size(struct ubifs_info *c)
err = fix_size_in_place(c, e); err = fix_size_in_place(c, e);
if (err) if (err)
return err; return err;
if (e->inode) iput(e->inode);
iput(e->inode);
} }
} }
......
...@@ -128,7 +128,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ...@@ -128,7 +128,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
if (err) if (err)
goto out_ino; goto out_ino;
inode->i_flags |= (S_NOCMTIME | S_NOATIME); inode->i_flags |= S_NOCMTIME;
#ifndef CONFIG_UBIFS_ATIME_SUPPORT
inode->i_flags |= S_NOATIME;
#endif
set_nlink(inode, le32_to_cpu(ino->nlink)); set_nlink(inode, le32_to_cpu(ino->nlink));
i_uid_write(inode, le32_to_cpu(ino->uid)); i_uid_write(inode, le32_to_cpu(ino->uid));
i_gid_write(inode, le32_to_cpu(ino->gid)); i_gid_write(inode, le32_to_cpu(ino->gid));
...@@ -2139,7 +2142,12 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags, ...@@ -2139,7 +2142,12 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
if (err) if (err)
goto out_deact; goto out_deact;
/* We do not support atime */ /* We do not support atime */
sb->s_flags |= MS_ACTIVE | MS_NOATIME; sb->s_flags |= MS_ACTIVE;
#ifndef CONFIG_UBIFS_ATIME_SUPPORT
sb->s_flags |= MS_NOATIME;
#else
ubifs_msg(c, "full atime support is enabled.");
#endif
} }
/* 'fill_super()' opens ubi again so we must close it here */ /* 'fill_super()' opens ubi again so we must close it here */
......
...@@ -198,11 +198,10 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c, ...@@ -198,11 +198,10 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
{ {
struct ubifs_znode *zn; struct ubifs_znode *zn;
zn = kmalloc(c->max_znode_sz, GFP_NOFS); zn = kmemdup(znode, c->max_znode_sz, GFP_NOFS);
if (unlikely(!zn)) if (unlikely(!zn))
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
memcpy(zn, znode, c->max_znode_sz);
zn->cnext = NULL; zn->cnext = NULL;
__set_bit(DIRTY_ZNODE, &zn->flags); __set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags); __clear_bit(COW_ZNODE, &zn->flags);
......
...@@ -858,9 +858,9 @@ struct ubifs_compressor { ...@@ -858,9 +858,9 @@ struct ubifs_compressor {
* @mod_dent: non-zero if the operation removes or modifies an existing * @mod_dent: non-zero if the operation removes or modifies an existing
* directory entry * directory entry
* @new_ino: non-zero if the operation adds a new inode * @new_ino: non-zero if the operation adds a new inode
* @new_ino_d: now much data newly created inode contains * @new_ino_d: how much data newly created inode contains
* @dirtied_ino: how many inodes the operation makes dirty * @dirtied_ino: how many inodes the operation makes dirty
* @dirtied_ino_d: now much data dirtied inode contains * @dirtied_ino_d: how much data dirtied inode contains
* @idx_growth: how much the index will supposedly grow * @idx_growth: how much the index will supposedly grow
* @data_growth: how much new data the operation will supposedly add * @data_growth: how much new data the operation will supposedly add
* @dd_growth: how much data that makes other data dirty the operation will * @dd_growth: how much data that makes other data dirty the operation will
...@@ -1746,6 +1746,9 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc); ...@@ -1746,6 +1746,9 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
/* file.c */ /* file.c */
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync); int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
int ubifs_setattr(struct dentry *dentry, struct iattr *attr); int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
#ifdef CONFIG_UBIFS_ATIME_SUPPORT
int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
#endif
/* dir.c */ /* dir.c */
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
......
...@@ -200,6 +200,7 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, ...@@ -200,6 +200,7 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
int err; int err;
struct ubifs_inode *host_ui = ubifs_inode(host); struct ubifs_inode *host_ui = ubifs_inode(host);
struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_inode *ui = ubifs_inode(inode);
void *buf = NULL;
struct ubifs_budget_req req = { .dirtied_ino = 2, struct ubifs_budget_req req = { .dirtied_ino = 2,
.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) }; .dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
...@@ -208,14 +209,17 @@ static int change_xattr(struct ubifs_info *c, struct inode *host, ...@@ -208,14 +209,17 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
if (err) if (err)
return err; return err;
kfree(ui->data); buf = kmemdup(value, size, GFP_NOFS);
ui->data = kmemdup(value, size, GFP_NOFS); if (!buf) {
if (!ui->data) {
err = -ENOMEM; err = -ENOMEM;
goto out_free; goto out_free;
} }
mutex_lock(&ui->ui_mutex);
kfree(ui->data);
ui->data = buf;
inode->i_size = ui->ui_size = size; inode->i_size = ui->ui_size = size;
ui->data_len = size; ui->data_len = size;
mutex_unlock(&ui->ui_mutex);
mutex_lock(&host_ui->ui_mutex); mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host); host->i_ctime = ubifs_current_time(host);
...@@ -409,6 +413,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ...@@ -409,6 +413,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
ubifs_assert(inode->i_size == ui->data_len); ubifs_assert(inode->i_size == ui->data_len);
ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len); ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
mutex_lock(&ui->ui_mutex);
if (buf) { if (buf) {
/* If @buf is %NULL we are supposed to return the length */ /* If @buf is %NULL we are supposed to return the length */
if (ui->data_len > size) { if (ui->data_len > size) {
...@@ -423,6 +428,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf, ...@@ -423,6 +428,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
err = ui->data_len; err = ui->data_len;
out_iput: out_iput:
mutex_unlock(&ui->ui_mutex);
iput(inode); iput(inode);
out_unlock: out_unlock:
kfree(xent); kfree(xent);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment