On 2014-03-18 12:50, Vyacheslav Dubeyko wrote:
> On Sun, 2014-03-16 at 11:47 +0100, Andreas Rohner wrote:
>
>> diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c
>> index 7adb15d..e7b19c40 100644
>> --- a/fs/nilfs2/dat.c
>> +++ b/fs/nilfs2/dat.c
>> @@ -445,6 +445,64 @@ int nilfs_dat_clean_snapshot_flag(struct inode *dat,
>> __u64 vblocknr)
>> }
>>
>> /**
>> + * nilfs_dat_is_live - checks if the virtual block number is alive
>
> What about nilfs_dat_block_is_alive?
Yes sounds good.
>> + * @dat: DAT file inode
>> + * @vblocknr: virtual block number
>> + *
>> + * Description: nilfs_dat_is_live() looks up the DAT entry for @vblocknr and
>> + * determines if the corresponding block is alive or not. This check ignores
>> + * snapshots and protection periods.
>> + *
>> + * Return Value: 1 if vblocknr is alive and 0 otherwise. On error, one
>> + * of the following negative error codes is returned.
>
> It is really bad idea to mess error codes and info return, from my point
> of view. Usually, it results in very buggy code in the place of call.
> Actually, you use binary nature of returned value.
>
> I think that it needs to rework ideology of this function. Maybe, it
> needs to return bool and to return error value as argument.
Yes that is true.
>> + *
>> + * %-EIO - I/O error.
>> + *
>> + * %-ENOMEM - Insufficient amount of memory available.
>> + *
>> + * %-ENOENT - A block number associated with @vblocknr does not exist.
>> + */
>> +int nilfs_dat_is_live(struct inode *dat, __u64 vblocknr)
>> +{
>> + struct buffer_head *entry_bh, *bh;
>> + struct nilfs_dat_entry *entry;
>> + sector_t blocknr;
>> + void *kaddr;
>> + int ret;
>> +
>> + ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
>> + if (ret < 0)
>> + return ret;
>> +
>> + if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) {
>> + bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh);
>> + if (bh) {
>> + WARN_ON(!buffer_uptodate(bh));
>> + brelse(entry_bh);
>> + entry_bh = bh;
>> + }
>> + }
>> +
>> + kaddr = kmap_atomic(entry_bh->b_page);
>> + entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
>> + blocknr = le64_to_cpu(entry->de_blocknr);
>> + if (blocknr == 0) {
>
> I suppose that zero is specially named constant?
I copied that code from nilfs_dat_translate(). So it is not my fault
that there isn't a properly named constant ;)
>> + ret = -ENOENT;
>> + goto out;
>> + }
>> +
>> +
>> + if (entry->de_end == cpu_to_le64(NILFS_CNO_MAX))
>> + ret = 1;
>> + else
>> + ret = 0;
>> +out:
>> + kunmap_atomic(kaddr);
>> + brelse(entry_bh);
>> + return ret;
>> +}
>> +
>> +/**
>> * nilfs_dat_translate - translate a virtual block number to a block number
>> * @dat: DAT file inode
>> * @vblocknr: virtual block number
>> diff --git a/fs/nilfs2/dat.h b/fs/nilfs2/dat.h
>> index a528024..51d44c0 100644
>> --- a/fs/nilfs2/dat.h
>> +++ b/fs/nilfs2/dat.h
>> @@ -31,6 +31,7 @@
>> struct nilfs_palloc_req;
>>
>> int nilfs_dat_translate(struct inode *, __u64, sector_t *);
>> +int nilfs_dat_is_live(struct inode *, __u64);
>>
>> int nilfs_dat_prepare_alloc(struct inode *, struct nilfs_palloc_req *);
>> void nilfs_dat_commit_alloc(struct inode *, struct nilfs_palloc_req *);
>> diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
>> index b9c5726..c32b896 100644
>> --- a/fs/nilfs2/inode.c
>> +++ b/fs/nilfs2/inode.c
>> @@ -86,6 +86,8 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff,
>> int err = 0, ret;
>> unsigned maxblocks = bh_result->b_size >> inode->i_blkbits;
>>
>> + bh_result->b_blocknr = 0;
>> +
>> down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
>> ret = nilfs_bmap_lookup_contig(ii->i_bmap, blkoff, &blknum, maxblocks);
>> up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem);
>> diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
>> index 0b62bf4..3603394 100644
>> --- a/fs/nilfs2/ioctl.c
>> +++ b/fs/nilfs2/ioctl.c
>> @@ -612,6 +612,12 @@ static int nilfs_ioctl_move_inode_block(struct inode
>> *inode,
>> brelse(bh);
>> return -EEXIST;
>> }
>> +
>> + if (nilfs_vdesc_snapshot(vdesc))
>> + set_buffer_nilfs_snapshot(bh);
>> + if (nilfs_vdesc_protection_period(vdesc))
>> + set_buffer_nilfs_protection_period(bh);
>> +
>> list_add_tail(&bh->b_assoc_buffers, buffers);
>> return 0;
>> }
>> diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h
>> index ef30c5c..8c34a31 100644
>> --- a/fs/nilfs2/page.h
>> +++ b/fs/nilfs2/page.h
>> @@ -36,13 +36,17 @@ enum {
>> BH_NILFS_Volatile,
>> BH_NILFS_Checked,
>> BH_NILFS_Redirected,
>> + BH_NILFS_Snapshot,
>> + BH_NILFS_Protection_Period,
>> };
>>
>> BUFFER_FNS(NILFS_Node, nilfs_node) /* nilfs node buffers */
>> BUFFER_FNS(NILFS_Volatile, nilfs_volatile)
>> BUFFER_FNS(NILFS_Checked, nilfs_checked) /* buffer is verified */
>> BUFFER_FNS(NILFS_Redirected, nilfs_redirected) /* redirected to a copy
>> */
>> -
>> +BUFFER_FNS(NILFS_Snapshot, nilfs_snapshot) /* belongs to a snapshot */
>> +BUFFER_FNS(NILFS_Protection_Period, nilfs_protection_period) /* protected by
>> + protection period */
>>
>> int __nilfs_clear_page_dirty(struct page *);
>>
>> diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c
>> index dc3a9efd..c72fc37 100644
>> --- a/fs/nilfs2/segbuf.c
>> +++ b/fs/nilfs2/segbuf.c
>> @@ -28,6 +28,7 @@
>> #include <linux/slab.h>
>> #include "page.h"
>> #include "segbuf.h"
>> +#include "sufile.h"
>>
>>
>> struct nilfs_write_info {
>> @@ -57,6 +58,8 @@ struct nilfs_segment_buffer *nilfs_segbuf_new(struct
>> super_block *sb)
>> INIT_LIST_HEAD(&segbuf->sb_segsum_buffers);
>> INIT_LIST_HEAD(&segbuf->sb_payload_buffers);
>> segbuf->sb_super_root = NULL;
>> + segbuf->sb_su_blocks = 0;
>> + segbuf->sb_su_blocks_cancel = 0;
>>
>> init_completion(&segbuf->sb_bio_event);
>> atomic_set(&segbuf->sb_err, 0);
>> @@ -82,6 +85,25 @@ void nilfs_segbuf_map(struct nilfs_segment_buffer
>> *segbuf, __u64 segnum,
>> segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;
>> }
>>
>> +int nilfs_segbuf_set_sui(struct nilfs_segment_buffer *segbuf,
>> + struct the_nilfs *nilfs)
>> +{
>> + struct nilfs_suinfo si;
>> + ssize_t err;
>> +
>> + err = nilfs_sufile_get_suinfo(nilfs->ns_sufile, segbuf->sb_segnum, &si,
>> + sizeof(si), 1);
>> + if (err != 1)
>
> If nilfs_sufile_get_suinfo() returns error then how it can be equal by
> one? What a mess?
Actually nilfs_sufile_get_suinfo() returns the number of segments
written on success and a negative error otherwise. So it returns both an
error and the number of segments. Since I requested one entry I compare
it to 1.
>
>> + return -1;
>
> It is really bad idea. Finally, caller will have -EPERM. Do you mean
> this here?
Hmm yes that is wrong. It should probably be something like:
if (err < 0)
return err;
else if (err != 1)
return -ENOENT;
>> +
>> + if (si.sui_nblocks == 0)
>> + si.sui_nblocks = segbuf->sb_pseg_start - segbuf->sb_fseg_start;
>> +
>> + segbuf->sb_su_blocks = si.sui_nblocks;
>> + segbuf->sb_su_blocks_cancel = si.sui_nblocks;
>> + return 0;
>> +}
>> +
>> /**
>> * nilfs_segbuf_map_cont - map a new log behind a given log
>> * @segbuf: new segment buffer
>> @@ -450,6 +472,9 @@ static int nilfs_segbuf_submit_bh(struct
>> nilfs_segment_buffer *segbuf,
>>
>> len = bio_add_page(wi->bio, bh->b_page, bh->b_size, bh_offset(bh));
>> if (len == bh->b_size) {
>> + lock_buffer(bh);
>> + map_bh(bh, segbuf->sb_super, wi->blocknr + wi->end);
>> + unlock_buffer(bh);
>> wi->end++;
>> return 0;
>> }
>> diff --git a/fs/nilfs2/segbuf.h b/fs/nilfs2/segbuf.h
>> index b04f08c..482bbad 100644
>> --- a/fs/nilfs2/segbuf.h
>> +++ b/fs/nilfs2/segbuf.h
>> @@ -83,6 +83,8 @@ struct nilfs_segment_buffer {
>> sector_t sb_fseg_start, sb_fseg_end;
>> sector_t sb_pseg_start;
>> unsigned sb_rest_blocks;
>> + __u32 sb_su_blocks_cancel;
>> + __s64 sb_su_blocks;
>>
>> /* Buffers */
>> struct list_head sb_segsum_buffers;
>> @@ -122,6 +124,8 @@ void nilfs_segbuf_map(struct nilfs_segment_buffer *,
>> __u64, unsigned long,
>> struct the_nilfs *);
>> void nilfs_segbuf_map_cont(struct nilfs_segment_buffer *segbuf,
>> struct nilfs_segment_buffer *prev);
>> +int nilfs_segbuf_set_sui(struct nilfs_segment_buffer *segbuf,
>> + struct the_nilfs *nilfs);
>> void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *, __u64,
>> struct the_nilfs *);
>> int nilfs_segbuf_reset(struct nilfs_segment_buffer *, unsigned, time_t,
>> __u64);
>> diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
>> index a1a1916..5d98a1c 100644
>> --- a/fs/nilfs2/segment.c
>> +++ b/fs/nilfs2/segment.c
>> @@ -1257,6 +1257,10 @@ static int nilfs_segctor_begin_construction(struct
>> nilfs_sc_info *sci,
>> }
>> nilfs_segbuf_set_next_segnum(segbuf, nextnum, nilfs);
>>
>> + err = nilfs_segbuf_set_sui(segbuf, nilfs);
>> + if (err)
>> + goto failed;
>> +
>> BUG_ON(!list_empty(&sci->sc_segbufs));
>> list_add_tail(&segbuf->sb_list, &sci->sc_segbufs);
>> sci->sc_segbuf_nblocks = segbuf->sb_rest_blocks;
>> @@ -1306,6 +1310,10 @@ static int nilfs_segctor_extend_segments(struct
>> nilfs_sc_info *sci,
>> segbuf->sb_sum.seg_seq = prev->sb_sum.seg_seq + 1;
>> nilfs_segbuf_set_next_segnum(segbuf, nextnextnum, nilfs);
>>
>> + err = nilfs_segbuf_set_sui(segbuf, nilfs);
>> + if (err)
>> + goto failed;
>> +
>> list_add_tail(&segbuf->sb_list, &list);
>> prev = segbuf;
>> }
>> @@ -1368,8 +1376,7 @@ static void nilfs_segctor_update_segusage(struct
>> nilfs_sc_info *sci,
>> int ret;
>>
>> list_for_each_entry(segbuf, &sci->sc_segbufs, sb_list) {
>> - live_blocks = segbuf->sb_sum.nblocks +
>> - (segbuf->sb_pseg_start - segbuf->sb_fseg_start);
>> + live_blocks = segbuf->sb_sum.nfileblk + segbuf->sb_su_blocks;
>> ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum,
>> live_blocks,
>> sci->sc_seg_ctime);
>> @@ -1383,9 +1390,9 @@ static void nilfs_cancel_segusage(struct list_head
>> *logs, struct inode *sufile)
>> int ret;
>>
>> segbuf = NILFS_FIRST_SEGBUF(logs);
>> +
>> ret = nilfs_sufile_set_segment_usage(sufile, segbuf->sb_segnum,
>> - segbuf->sb_pseg_start -
>> - segbuf->sb_fseg_start, 0);
>> + segbuf->sb_su_blocks_cancel, 0);
>> WARN_ON(ret); /* always succeed because the segusage is dirty */
>>
>> list_for_each_entry_continue(segbuf, logs, sb_list) {
>> @@ -1477,7 +1484,9 @@ nilfs_segctor_update_payload_blocknr(struct
>> nilfs_sc_info *sci,
>> struct nilfs_segment_buffer *segbuf,
>> int mode)
>> {
>> + struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
>> struct inode *inode = NULL;
>> + struct nilfs_inode_info *ii;
>> sector_t blocknr;
>> unsigned long nfinfo = segbuf->sb_sum.nfinfo;
>> unsigned long nblocks = 0, ndatablk = 0;
>> @@ -1487,7 +1496,9 @@ nilfs_segctor_update_payload_blocknr(struct
>> nilfs_sc_info *sci,
>> union nilfs_binfo binfo;
>> struct buffer_head *bh, *bh_org;
>> ino_t ino = 0;
>> - int err = 0;
>> + int gc_inode = 0, err = 0;
>> + __u64 segnum, prev_segnum = 0, dectime = 0, maxdectime = 0;
>> + __u32 blkcount = 0;
>>
>> if (!nfinfo)
>> goto out;
>> @@ -1508,6 +1519,17 @@ nilfs_segctor_update_payload_blocknr(struct
>> nilfs_sc_info *sci,
>>
>> inode = bh->b_page->mapping->host;
>>
>> + ii = NILFS_I(inode);
>> + gc_inode = test_bit(NILFS_I_GCINODE, &ii->i_state);
>> + dectime = sci->sc_seg_ctime;
>
> The dectime sounds not very good for me.
I decrement the block counter in the SUFILE here. And this is the time
it got decremented. But I guess I could think of something better...
>> + /* no update of lastdec necessary */
>> + if (ino == NILFS_DAT_INO || ino == NILFS_SUFILE_INO ||
>> + ino == NILFS_CPFILE_INO)
>> + dectime = 0;
>
> What about such?
>
> if (ino == NILFS_DAT_INO ||
> ino == NILFS_SUFILE_INO ||
> ino == NILFS_CPFILE_INO)
> dectime = 0;
>
> But really I prefer to see small check function (is_metadata_file(), for
> example).
Ok.
>> +
>> + if (dectime > maxdectime)
>> + maxdectime = dectime;
>> +
>> if (mode == SC_LSEG_DSYNC)
>> sc_op = &nilfs_sc_dsync_ops;
>> else if (ino == NILFS_DAT_INO)
>> @@ -1515,6 +1537,39 @@ nilfs_segctor_update_payload_blocknr(struct
>> nilfs_sc_info *sci,
>> else /* file blocks */
>> sc_op = &nilfs_sc_file_ops;
>> }
>> +
>> + segnum = nilfs_get_segnum_of_block(nilfs, bh->b_blocknr);
>> + if (!gc_inode && bh->b_blocknr > 0 &&
>> + (ino == NILFS_DAT_INO || !buffer_nilfs_node(bh)) &&
>> + segnum < nilfs->ns_nsegments) {
>> +
>> + if (segnum != prev_segnum) {
>> + if (blkcount) {
>> + nilfs_sufile_add_segment_usage(
>> + nilfs->ns_sufile,
>> + prev_segnum,
>> + -((__s64)blkcount),
>> + maxdectime);
>
> It is really bad code style. Usually, it means necessity to refactor
> function's code. Otherwise, it is really hard to understand the code.
>
>> + }
>> + prev_segnum = segnum;
>> + blkcount = 0;
>> + maxdectime = dectime;
>> + }
>> +
>> +
>> + if (segnum == segbuf->sb_segnum)
>> + segbuf->sb_su_blocks--;
>> + else
>> + ++blkcount;
>> + } else if (gc_inode && bh->b_blocknr > 0) {
>> + /* check again if gc blocks are alive */
>> + if (!buffer_nilfs_snapshot(bh) &&
>> + (buffer_nilfs_protection_period(bh) ||
>> + !nilfs_dat_is_live(nilfs->ns_dat,
>> + bh->b_blocknr)))
>> + segbuf->sb_su_blocks--;
>
> Ahhhhh. Again and again. :) Bad code style. You need to improve your
> taste. :)
Ok admittedly that part could use a little bit of refactoring. It grew
more and more complex during development. At the beginning it was just a
simple if-statement and a function call.
>> + }
>> +
>> bh_org = bh;
>> get_bh(bh_org);
>> err = nilfs_bmap_assign(NILFS_I(inode)->i_bmap, &bh, blocknr,
>> @@ -1538,6 +1593,10 @@ nilfs_segctor_update_payload_blocknr(struct
>> nilfs_sc_info *sci,
>> } else if (ndatablk > 0)
>> ndatablk--;
>> }
>> +
>> + if (blkcount)
>> + nilfs_sufile_add_segment_usage(nilfs->ns_sufile, prev_segnum,
>> + -((__s64)blkcount), maxdectime);
>
> Such way -((__s64)blkcount) looks not very good. Very complex and
> confusing construction at whole, from my viewpoint.
Hmm yes I could make blkcount a __s64 from the start and decrement it
instead of incrementing it.
Best regards,
Andreas Rohner
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html