nilfs2: add nilfs_sufile_set_suinfo to update segment usage
Introduce nilfs_sufile_set_suinfo(), which expects an array of nilfs_suinfo_update structures and updates the segment usage information accordingly. This is basically a helper function for the newly introduced NILFS_IOCTL_SET_SUINFO ioctl. [konishi.ryusuke@lab.ntt.co.jp: use put_bh() instead of brelse() because we know bh != NULL] Signed-off-by: Andreas Rohner <andreas.rohner@gmx.net> Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
90ccf7dde9
Коммит
00e9ffcd27
|
@ -869,6 +869,137 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nilfs_sufile_set_suinfo - sets segment usage info
|
||||||
|
* @sufile: inode of segment usage file
|
||||||
|
* @buf: array of suinfo_update
|
||||||
|
* @supsz: byte size of suinfo_update
|
||||||
|
* @nsup: size of suinfo_update array
|
||||||
|
*
|
||||||
|
* Description: Takes an array of nilfs_suinfo_update structs and updates
|
||||||
|
* segment usage accordingly. Only the fields indicated by the sup_flags
|
||||||
|
* are updated.
|
||||||
|
*
|
||||||
|
* Return Value: On success, 0 is returned. On error, one of the
|
||||||
|
* following negative error codes is returned.
|
||||||
|
*
|
||||||
|
* %-EIO - I/O error.
|
||||||
|
*
|
||||||
|
* %-ENOMEM - Insufficient amount of memory available.
|
||||||
|
*
|
||||||
|
* %-EINVAL - Invalid values in input (segment number, flags or nblocks)
|
||||||
|
*/
|
||||||
|
ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
|
||||||
|
unsigned supsz, size_t nsup)
|
||||||
|
{
|
||||||
|
struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
|
||||||
|
struct buffer_head *header_bh, *bh;
|
||||||
|
struct nilfs_suinfo_update *sup, *supend = buf + supsz * nsup;
|
||||||
|
struct nilfs_segment_usage *su;
|
||||||
|
void *kaddr;
|
||||||
|
unsigned long blkoff, prev_blkoff;
|
||||||
|
int cleansi, cleansu, dirtysi, dirtysu;
|
||||||
|
long ncleaned = 0, ndirtied = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (unlikely(nsup == 0))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (sup = buf; sup < supend; sup = (void *)sup + supsz) {
|
||||||
|
if (sup->sup_segnum >= nilfs->ns_nsegments
|
||||||
|
|| (sup->sup_flags &
|
||||||
|
(~0UL << __NR_NILFS_SUINFO_UPDATE_FIELDS))
|
||||||
|
|| (nilfs_suinfo_update_nblocks(sup) &&
|
||||||
|
sup->sup_sui.sui_nblocks >
|
||||||
|
nilfs->ns_blocks_per_segment))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
down_write(&NILFS_MDT(sufile)->mi_sem);
|
||||||
|
|
||||||
|
ret = nilfs_sufile_get_header_block(sufile, &header_bh);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_sem;
|
||||||
|
|
||||||
|
sup = buf;
|
||||||
|
blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
|
||||||
|
ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_header;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
kaddr = kmap_atomic(bh->b_page);
|
||||||
|
su = nilfs_sufile_block_get_segment_usage(
|
||||||
|
sufile, sup->sup_segnum, bh, kaddr);
|
||||||
|
|
||||||
|
if (nilfs_suinfo_update_lastmod(sup))
|
||||||
|
su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
|
||||||
|
|
||||||
|
if (nilfs_suinfo_update_nblocks(sup))
|
||||||
|
su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
|
||||||
|
|
||||||
|
if (nilfs_suinfo_update_flags(sup)) {
|
||||||
|
/*
|
||||||
|
* Active flag is a virtual flag projected by running
|
||||||
|
* nilfs kernel code - drop it not to write it to
|
||||||
|
* disk.
|
||||||
|
*/
|
||||||
|
sup->sup_sui.sui_flags &=
|
||||||
|
~(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
|
||||||
|
|
||||||
|
cleansi = nilfs_suinfo_clean(&sup->sup_sui);
|
||||||
|
cleansu = nilfs_segment_usage_clean(su);
|
||||||
|
dirtysi = nilfs_suinfo_dirty(&sup->sup_sui);
|
||||||
|
dirtysu = nilfs_segment_usage_dirty(su);
|
||||||
|
|
||||||
|
if (cleansi && !cleansu)
|
||||||
|
++ncleaned;
|
||||||
|
else if (!cleansi && cleansu)
|
||||||
|
--ncleaned;
|
||||||
|
|
||||||
|
if (dirtysi && !dirtysu)
|
||||||
|
++ndirtied;
|
||||||
|
else if (!dirtysi && dirtysu)
|
||||||
|
--ndirtied;
|
||||||
|
|
||||||
|
su->su_flags = cpu_to_le32(sup->sup_sui.sui_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
kunmap_atomic(kaddr);
|
||||||
|
|
||||||
|
sup = (void *)sup + supsz;
|
||||||
|
if (sup >= supend)
|
||||||
|
break;
|
||||||
|
|
||||||
|
prev_blkoff = blkoff;
|
||||||
|
blkoff = nilfs_sufile_get_blkoff(sufile, sup->sup_segnum);
|
||||||
|
if (blkoff == prev_blkoff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* get different block */
|
||||||
|
mark_buffer_dirty(bh);
|
||||||
|
put_bh(bh);
|
||||||
|
ret = nilfs_mdt_get_block(sufile, blkoff, 1, NULL, &bh);
|
||||||
|
if (unlikely(ret < 0))
|
||||||
|
goto out_mark;
|
||||||
|
}
|
||||||
|
mark_buffer_dirty(bh);
|
||||||
|
put_bh(bh);
|
||||||
|
|
||||||
|
out_mark:
|
||||||
|
if (ncleaned || ndirtied) {
|
||||||
|
nilfs_sufile_mod_counter(header_bh, (u64)ncleaned,
|
||||||
|
(u64)ndirtied);
|
||||||
|
NILFS_SUI(sufile)->ncleansegs += ncleaned;
|
||||||
|
}
|
||||||
|
nilfs_mdt_mark_dirty(sufile);
|
||||||
|
out_header:
|
||||||
|
put_bh(header_bh);
|
||||||
|
out_sem:
|
||||||
|
up_write(&NILFS_MDT(sufile)->mi_sem);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nilfs_sufile_read - read or get sufile inode
|
* nilfs_sufile_read - read or get sufile inode
|
||||||
* @sb: super block instance
|
* @sb: super block instance
|
||||||
|
|
|
@ -44,6 +44,7 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
|
||||||
int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
|
int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
|
||||||
ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
|
ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
|
||||||
size_t);
|
size_t);
|
||||||
|
ssize_t nilfs_sufile_set_suinfo(struct inode *, void *, unsigned , size_t);
|
||||||
|
|
||||||
int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
|
int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
|
||||||
void (*dofunc)(struct inode *, __u64,
|
void (*dofunc)(struct inode *, __u64,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче