nilfs2: add sufile function that can modify multiple segment usages
This is a preparation for the later cleanup patch ("nilfs2: remove list of freeing segments"). This adds nilfs_sufile_updatev() to sufile, which can modify multiple segment usages at a time. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*
|
*
|
||||||
* Written by Koji Sato <koji@osrg.net>.
|
* Written by Koji Sato <koji@osrg.net>.
|
||||||
|
* Rivised by Ryusuke Konishi <ryusuke@osrg.net>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@@ -108,6 +109,102 @@ static void nilfs_sufile_mod_counter(struct buffer_head *header_bh,
|
|||||||
nilfs_mdt_mark_buffer_dirty(header_bh);
|
nilfs_mdt_mark_buffer_dirty(header_bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nilfs_sufile_updatev - modify multiple segment usages at a time
|
||||||
|
* @sufile: inode of segment usage file
|
||||||
|
* @segnumv: array of segment numbers
|
||||||
|
* @nsegs: size of @segnumv array
|
||||||
|
* @create: creation flag
|
||||||
|
* @ndone: place to store number of modified segments on @segnumv
|
||||||
|
* @dofunc: primitive operation for the update
|
||||||
|
*
|
||||||
|
* Description: nilfs_sufile_updatev() repeatedly calls @dofunc
|
||||||
|
* against the given array of segments. The @dofunc is called with
|
||||||
|
* buffers of a header block and the sufile block in which the target
|
||||||
|
* segment usage entry is contained. If @ndone is given, the number
|
||||||
|
* of successfully modified segments from the head is stored in the
|
||||||
|
* place @ndone points to.
|
||||||
|
*
|
||||||
|
* Return Value: On success, zero is returned. On error, one of the
|
||||||
|
* following negative error codes is returned.
|
||||||
|
*
|
||||||
|
* %-EIO - I/O error.
|
||||||
|
*
|
||||||
|
* %-ENOMEM - Insufficient amount of memory available.
|
||||||
|
*
|
||||||
|
* %-ENOENT - Given segment usage is in hole block (may be returned if
|
||||||
|
* @create is zero)
|
||||||
|
*
|
||||||
|
* %-EINVAL - Invalid segment usage number
|
||||||
|
*/
|
||||||
|
int nilfs_sufile_updatev(struct inode *sufile, __u64 *segnumv, size_t nsegs,
|
||||||
|
int create, size_t *ndone,
|
||||||
|
void (*dofunc)(struct inode *, __u64,
|
||||||
|
struct buffer_head *,
|
||||||
|
struct buffer_head *))
|
||||||
|
{
|
||||||
|
struct buffer_head *header_bh, *bh;
|
||||||
|
unsigned long blkoff, prev_blkoff;
|
||||||
|
__u64 *seg;
|
||||||
|
size_t nerr = 0, n = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (unlikely(nsegs == 0))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
down_write(&NILFS_MDT(sufile)->mi_sem);
|
||||||
|
for (seg = segnumv; seg < segnumv + nsegs; seg++) {
|
||||||
|
if (unlikely(*seg >= nilfs_sufile_get_nsegments(sufile))) {
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"%s: invalid segment number: %llu\n", __func__,
|
||||||
|
(unsigned long long)*seg);
|
||||||
|
nerr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nerr > 0) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_sem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nilfs_sufile_get_header_block(sufile, &header_bh);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_sem;
|
||||||
|
|
||||||
|
seg = segnumv;
|
||||||
|
blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
|
||||||
|
ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out_header;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
dofunc(sufile, *seg, header_bh, bh);
|
||||||
|
|
||||||
|
if (++seg >= segnumv + nsegs)
|
||||||
|
break;
|
||||||
|
prev_blkoff = blkoff;
|
||||||
|
blkoff = nilfs_sufile_get_blkoff(sufile, *seg);
|
||||||
|
if (blkoff == prev_blkoff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* get different block */
|
||||||
|
brelse(bh);
|
||||||
|
ret = nilfs_mdt_get_block(sufile, blkoff, create, NULL, &bh);
|
||||||
|
if (unlikely(ret < 0))
|
||||||
|
goto out_header;
|
||||||
|
}
|
||||||
|
brelse(bh);
|
||||||
|
|
||||||
|
out_header:
|
||||||
|
n = seg - segnumv;
|
||||||
|
brelse(header_bh);
|
||||||
|
out_sem:
|
||||||
|
up_write(&NILFS_MDT(sufile)->mi_sem);
|
||||||
|
out:
|
||||||
|
if (ndone)
|
||||||
|
*ndone = n;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
|
int nilfs_sufile_update(struct inode *sufile, __u64 segnum, int create,
|
||||||
void (*dofunc)(struct inode *, __u64,
|
void (*dofunc)(struct inode *, __u64,
|
||||||
struct buffer_head *,
|
struct buffer_head *,
|
||||||
|
@@ -46,6 +46,10 @@ int nilfs_sufile_get_ncleansegs(struct inode *, unsigned long *);
|
|||||||
ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *,
|
ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, struct nilfs_suinfo *,
|
||||||
size_t);
|
size_t);
|
||||||
|
|
||||||
|
int nilfs_sufile_updatev(struct inode *, __u64 *, size_t, int, size_t *,
|
||||||
|
void (*dofunc)(struct inode *, __u64,
|
||||||
|
struct buffer_head *,
|
||||||
|
struct buffer_head *));
|
||||||
int nilfs_sufile_update(struct inode *, __u64, int,
|
int nilfs_sufile_update(struct inode *, __u64, int,
|
||||||
void (*dofunc)(struct inode *, __u64,
|
void (*dofunc)(struct inode *, __u64,
|
||||||
struct buffer_head *,
|
struct buffer_head *,
|
||||||
|
Reference in New Issue
Block a user