Skip to contentSkip to conversation

nilfs2: implement tracking of live blocks

PATCH In review Andreas Rohner 3 participants 34 messages Mar 16, 2014 – Mar 18, 2014 18 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover nilfs2: implement tracking of live blocks

Hi,

This patch set implements the tracking of live blocks in segments. This information is crucial in implementing better GC policies, because now the policies can make informed decisions about which segments have the biggest number of reclaimable blocks.

The difficulty in tracking live blocks is the fact, that any block can belong to any number of snapshots and snapshots can be deleted and created at any time. A block belongs to a snapshot, if the checkpoint number lies between de_start and de_end of the block. So if a new snapshot is created, all the reclaimable blocks belonging to it are no longer reclaimable and therefore the live block counter of the corresponding segment must be incremented. Conversely if a snapshot is removed, all the reclaimable blocks belonging to it should really be counted as reclaimable again and the counter must be decremented. But if one block belongs to two or more snapshots the counter must only be incremented once for the first and decremented once for the last snapshot.

To achieve this I used the de_rsv field of nilfs_dat_entry to store one of the snapshot numbers. Every time a snapshot is created/removed the whole DAT-File is scanned and de_rsv is updated if the snapshot number is between de_start and de_end. But one block can belong to an arbitrary number of snapshots. Here I use the fact, that the snapshot list is organized as a sorted linked list. So by knowing the previous and the next snapshot number it is possible to reliably determine, if a block is reclaimable or belongs to another snapshot.

It is of course unacceptable to update the whole DAT-File to create one snapshot. So only reclaimable blocks are updated. But this leads to certain situations, where the counters won't be accurate. The userspace GC should be capable of compensating and correcting the inaccurate values.

Another problem is the protection period in the userspace GC. The kernel doesn't know anything about the userspace protection period, and it is therefore not reflected in the number of live blocks in a segment. For example if the GC policy chooses a segment that seems to have a lot of reclaimable blocks, it could turn out, that all of those blocks are still protected by the protection period.

To overcome this problem I added an additional field to su_lastdec to the segment usage information. Whenever the number of live blocks in a segment is adjusted su_lastdec is set to the current timestamp. If the number of live blocks was adjusted within the protection period, then the userspace GC policy can recognize it and choose a different segment.

Compatibility Issues:
1. su_nblocks is reused to represent the number of live blocks old nilfs-utils would break the file system.
2. the vd_pad field of nilfs_vdesc was not initialized to 0 so old nilfs-utils could send arbitrary flags to the kernel

Benchmark Results:

The benchmark replays NFS-Traces to simulate a real file system load. The file system is filled up to 20% capacity and then the NFS-Traces are replayed. In parallel every 5 minutes random checkpoints are turned into snapshots. After 15 minutes the snapshot is turned back into a checkpoint.

Greedy-Policy-Runtime:       6221.712s
Cost-Benefit-Policy-Runtime: 6874.840s
Timestamp-Policy-Runtime:    13179.626s

Best regards,
Andreas Rohner

---
Andreas Rohner (6):
nilfs2: add helper function to go through all entries of meta data
file
nilfs2: add new timestamp to seg usage and function to change
su_nblocks
nilfs2: scan dat entries at snapshot creation/deletion time
nilfs2: add ioctl() to clean snapshot flags from dat entries
nilfs2: add counting of live blocks for blocks that are overwritten
nilfs2: add counting of live blocks for deleted files

 fs/nilfs2/alloc.c         | 121 +++++++++++++++++++++++++
 fs/nilfs2/alloc.h         |   6 ++
 fs/nilfs2/bmap.c          |   8 +-
 fs/nilfs2/bmap.h          |   2 +-
 fs/nilfs2/btree.c         |   3 +-
 fs/nilfs2/cpfile.c        |   7 ++
 fs/nilfs2/dat.c           | 225 +++++++++++++++++++++++++++++++++++++++++++++-
 fs/nilfs2/dat.h           |  32 ++++++-
 fs/nilfs2/direct.c        |   3 +-
 fs/nilfs2/inode.c         |   2 +
 fs/nilfs2/ioctl.c         | 109 +++++++++++++++++++++-
 fs/nilfs2/mdt.c           |   5 +-
 fs/nilfs2/page.h          |   6 +-
 fs/nilfs2/segbuf.c        |  25 ++++++
 fs/nilfs2/segbuf.h        |   4 +
 fs/nilfs2/segment.c       |  69 ++++++++++++--
 fs/nilfs2/sufile.c        |  86 +++++++++++++++++-
 fs/nilfs2/sufile.h        |  18 ++++
 include/linux/nilfs2_fs.h |  65 +++++++++++++-
 19 files changed, 772 insertions(+), 24 deletions(-)
Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

PATCH 1/6 nilfs2: add helper function to go through all entries of meta data file

This patch introduces the nilfs_palloc_scan_entries() function, which takes an inode of one of nilfs' meta data files and iterates through all of its entries. For each entry the callback function pointer that is given as a parameter is called. The data parameter is passed to the callback function, so that it may receive parameters and return results.

---
 fs/nilfs2/alloc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/alloc.h |   6 +++
 2 files changed, 127 insertions(+)
fs/nilfs2/alloc.c +121 -0
index 741fd02..0edd85a 100644
@@ -545,6 +545,127 @@ int nilfs_palloc_prepare_alloc_entry(struct inode *inode,
 }
 
 /**
+ * nilfs_palloc_scan_entries - scan through every entry and execute dofunc
+ * @inode: inode of metadata file using this allocator
+ * @dofunc: function executed for every entry
+ * @data: data pointer passed to dofunc
+ *
+ * Description: nilfs_palloc_scan_entries() walks through every allocated entry
+ * of a metadata file and executes dofunc on it. It passes a data pointer to
+ * dofunc, which can be used as an input parameter or for returning of results.
+ *
+ * Return Value: On success, 0 is returned. On error, a
+ * negative error code is returned.
+ */
+int nilfs_palloc_scan_entries(struct inode *inode,
+			      void (*dofunc)(struct inode *,
+					     struct nilfs_palloc_req *,
+					     void *),
+			      void *data)
+{
+	struct buffer_head *desc_bh, *bitmap_bh;
+	struct nilfs_palloc_group_desc *desc;
+	struct nilfs_palloc_req req;
+	unsigned char *bitmap;
+	void *desc_kaddr, *bitmap_kaddr;
+	unsigned long group, maxgroup, ngroups;
+	unsigned long n, m, entries_per_group, groups_per_desc_block;
+	unsigned long i, j, pos;
+	unsigned long blkoff, prev_blkoff;
+	int ret;
+
+	ngroups = nilfs_palloc_groups_count(inode);
+	maxgroup = ngroups - 1;
+	entries_per_group = nilfs_palloc_entries_per_group(inode);
+	groups_per_desc_block = nilfs_palloc_groups_per_desc_block(inode);
+
+	for (group = 0; group < ngroups;) {
+		ret = nilfs_palloc_get_desc_block(inode, group, 0, &desc_bh);
+		if (ret == -ENOENT)
+			return 0;
+		else if (ret < 0)
+			return ret;
+		req.pr_desc_bh = desc_bh;
+		desc_kaddr = kmap(desc_bh->b_page);
+		desc = nilfs_palloc_block_get_group_desc(inode, group,
+							 desc_bh, desc_kaddr);
+		n = nilfs_palloc_rest_groups_in_desc_block(inode, group,
+							   maxgroup);
+
+		for (i = 0; i < n; i++, desc++, group++) {
+			m = entries_per_group -
+					nilfs_palloc_group_desc_nfrees(inode,
+							group, desc);
+			if (!m)
+				continue;
+
+			ret = nilfs_palloc_get_bitmap_block(
+				inode, group, 0, &bitmap_bh);
+			if (ret == -ENOENT) {
+				ret = 0;
+				goto out_desc;
+			} else if (ret < 0)
+				goto out_desc;
+
+			req.pr_bitmap_bh = bitmap_bh;
+			bitmap_kaddr = kmap(bitmap_bh->b_page);
+			bitmap = bitmap_kaddr + bh_offset(bitmap_bh);
+			/* entry blkoff is always bigger than 0 */
+			blkoff = 0;
+			pos = 0;
+
+			for (j = 0; j < m; ++j, ++pos) {
+				pos = nilfs_find_next_bit(bitmap,
+						entries_per_group, pos);
+
+				if (pos >= entries_per_group)
+					break;
+
+				/* found an entry */
+				req.pr_entry_nr =
+					entries_per_group * group + pos;
+
+				prev_blkoff = blkoff;
+				blkoff = nilfs_palloc_entry_blkoff(inode,
+							req.pr_entry_nr);
+
+				if (blkoff != prev_blkoff) {
+					if (prev_blkoff)
+						brelse(req.pr_entry_bh);
+
+					ret = nilfs_palloc_get_entry_block(
+							inode, req.pr_entry_nr,
+							0, &req.pr_entry_bh);
+					if (ret < 0)
+						goto out_entry;
+				}
+
+				dofunc(inode, &req, data);
+			}
+
+			if (blkoff)
+				brelse(req.pr_entry_bh);
+			kunmap(bitmap_bh->b_page);
+			brelse(bitmap_bh);
+		}
+
+		kunmap(desc_bh->b_page);
+		brelse(desc_bh);
+	}
+
+	return 0;
+
+out_entry:
+	kunmap(bitmap_bh->b_page);
+	brelse(bitmap_bh);
+
+out_desc:
+	kunmap(desc_bh->b_page);
+	brelse(desc_bh);
+	return ret;
+}
+
+/**
  * nilfs_palloc_commit_alloc_entry - finish allocation of a persistent object
  * @inode: inode of metadata file using this allocator
  * @req: nilfs_palloc_req structure exchanged for the allocation
fs/nilfs2/alloc.h +6 -0
index 4bd6451..0592035 100644
@@ -77,6 +77,7 @@ int nilfs_palloc_freev(struct inode *, __u64 *, size_t);
 #define nilfs_set_bit_atomic		ext2_set_bit_atomic
 #define nilfs_clear_bit_atomic		ext2_clear_bit_atomic
 #define nilfs_find_next_zero_bit	find_next_zero_bit_le
+#define nilfs_find_next_bit			find_next_bit_le
 
 /**
  * struct nilfs_bh_assoc - block offset and buffer head association
@@ -106,5 +107,10 @@ void nilfs_palloc_setup_cache(struct inode *inode,
 			      struct nilfs_palloc_cache *cache);
 void nilfs_palloc_clear_cache(struct inode *inode);
 void nilfs_palloc_destroy_cache(struct inode *inode);
+int nilfs_palloc_scan_entries(struct inode *,
+			      void (*dofunc)(struct inode *,
+					     struct nilfs_palloc_req *,
+					     void *),
+			      void *);
 
 #endif	/* _NILFS_ALLOC_H */
Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): 2adbf1034ab4b129223553746577f6ec0e699869.1394966729.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#4 lore raw

Re: [PATCH 1/6] nilfs2: add helper function to go through all entries of meta data file

Quoted 40 lines · Andreas Rohner

This patch introduces the nilfs_palloc_scan_entries() function, which takes an inode of one of nilfs' meta data files and iterates through all of its entries. For each entry the callback function pointer that is given as a parameter is called. The data parameter is passed to the callback function, so that it may receive parameters and return results.

---
 fs/nilfs2/alloc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/alloc.h |   6 +++
 2 files changed, 127 insertions(+)
fs/nilfs2/alloc.c +19 -0
index 741fd02..0edd85a 100644
@@ -545,6 +545,127 @@ int nilfs_palloc_prepare_alloc_entry(struct inode *inode,
 }
 
 /**
+ * nilfs_palloc_scan_entries - scan through every entry and execute dofunc
+ * @inode: inode of metadata file using this allocator
+ * @dofunc: function executed for every entry
+ * @data: data pointer passed to dofunc
+ *
+ * Description: nilfs_palloc_scan_entries() walks through every allocated entry
+ * of a metadata file and executes dofunc on it. It passes a data pointer to
+ * dofunc, which can be used as an input parameter or for returning of results.
+ *
+ * Return Value: On success, 0 is returned. On error, a
+ * negative error code is returned.
+ */
+int nilfs_palloc_scan_entries(struct inode *inode,
+			      void (*dofunc)(struct inode *,
+					     struct nilfs_palloc_req *,
+					     void *),
+			      void *data)
+{
+	struct buffer_head *desc_bh, *bitmap_bh;

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 576

Quoted 10 lines
fs/nilfs2/alloc.c +10 -0
+	struct nilfs_palloc_group_desc *desc;
+	struct nilfs_palloc_req req;
+	unsigned char *bitmap;
+	void *desc_kaddr, *bitmap_kaddr;
+	unsigned long group, maxgroup, ngroups;
+	unsigned long n, m, entries_per_group, groups_per_desc_block;
+	unsigned long i, j, pos;
+	unsigned long blkoff, prev_blkoff;
+	int ret;
+

I think that it really makes sense to split this function's code between several small functions. It improves code style and readability of function. Moreover, it makes function more easy understandable.

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 584

Quoted 8 lines
fs/nilfs2/alloc.c +8 -0
+	ngroups = nilfs_palloc_groups_count(inode);
+	maxgroup = ngroups - 1;
+	entries_per_group = nilfs_palloc_entries_per_group(inode);
+	groups_per_desc_block = nilfs_palloc_groups_per_desc_block(inode);
+
+	for (group = 0; group < ngroups;) {
+		ret = nilfs_palloc_get_desc_block(inode, group, 0, &desc_bh);
+		if (ret == -ENOENT)

I suggest to add comment here.

Quoted 4 lines
fs/nilfs2/alloc.c +4 -0
+			return 0;
+		else if (ret < 0)
+			return ret;
+		req.pr_desc_bh = desc_bh;

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 598

Quoted 10 lines
fs/nilfs2/alloc.c +10 -0
+		desc_kaddr = kmap(desc_bh->b_page);
+		desc = nilfs_palloc_block_get_group_desc(inode, group,
+							 desc_bh, desc_kaddr);
+		n = nilfs_palloc_rest_groups_in_desc_block(inode, group,
+							   maxgroup);
+
+		for (i = 0; i < n; i++, desc++, group++) {
+			m = entries_per_group -
+					nilfs_palloc_group_desc_nfrees(inode,
+							group, desc);

Looks weird. It makes sense to split on several functions or to use variable.

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 603

Quoted 5 lines
fs/nilfs2/alloc.c +5 -0
+			if (!m)
+				continue;
+
+			ret = nilfs_palloc_get_bitmap_block(
+				inode, group, 0, &bitmap_bh);

Ditto. Looks weird.

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 606

Quoted 3 lines
fs/nilfs2/alloc.c +3 -0
+			if (ret == -ENOENT) {
+				ret = 0;
+				goto out_desc;

It needs to add comment here. Otherwise, it looks weird because anyway we go to out_desc. Maybe to combine:

if (unlikely(ret < 0)) {
	if (ret == -ENOENT)
		ret = 0;
	goto out_desc;
}

Anyway, it needs to comment why we assign zero for the case of -ENOENT.

Quoted 22 lines
fs/nilfs2/alloc.c +22 -0
+			} else if (ret < 0)
+				goto out_desc;
+
+			req.pr_bitmap_bh = bitmap_bh;
+			bitmap_kaddr = kmap(bitmap_bh->b_page);
+			bitmap = bitmap_kaddr + bh_offset(bitmap_bh);
+			/* entry blkoff is always bigger than 0 */
+			blkoff = 0;
+			pos = 0;
+
+			for (j = 0; j < m; ++j, ++pos) {
+				pos = nilfs_find_next_bit(bitmap,
+						entries_per_group, pos);
+
+				if (pos >= entries_per_group)
+					break;
+
+				/* found an entry */
+				req.pr_entry_nr =
+					entries_per_group * group + pos;
+
+				prev_blkoff = blkoff;

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 638

Quoted 10 lines
fs/nilfs2/alloc.c +10 -0
+				blkoff = nilfs_palloc_entry_blkoff(inode,
+							req.pr_entry_nr);
+
+				if (blkoff != prev_blkoff) {
+					if (prev_blkoff)
+						brelse(req.pr_entry_bh);
+
+					ret = nilfs_palloc_get_entry_block(
+							inode, req.pr_entry_nr,
+							0, &req.pr_entry_bh);

Ahhhh. Look weird. :) Split on small functions with clear names, anyway. It really improves the code from any point of view.

Thanks,
Vyacheslav Dubeyko.

Quoted 46 lines
fs/nilfs2/alloc.c +30 -0
+					if (ret < 0)
+						goto out_entry;
+				}
+
+				dofunc(inode, &req, data);
+			}
+
+			if (blkoff)
+				brelse(req.pr_entry_bh);
+			kunmap(bitmap_bh->b_page);
+			brelse(bitmap_bh);
+		}
+
+		kunmap(desc_bh->b_page);
+		brelse(desc_bh);
+	}
+
+	return 0;
+
+out_entry:
+	kunmap(bitmap_bh->b_page);
+	brelse(bitmap_bh);
+
+out_desc:
+	kunmap(desc_bh->b_page);
+	brelse(desc_bh);
+	return ret;
+}
+
+/**
  * nilfs_palloc_commit_alloc_entry - finish allocation of a persistent object
  * @inode: inode of metadata file using this allocator
  * @req: nilfs_palloc_req structure exchanged for the allocation
fs/nilfs2/alloc.h +1 -0
index 4bd6451..0592035 100644
@@ -77,6 +77,7 @@ int nilfs_palloc_freev(struct inode *, __u64 *, size_t);
 #define nilfs_set_bit_atomic		ext2_set_bit_atomic
 #define nilfs_clear_bit_atomic		ext2_clear_bit_atomic
 #define nilfs_find_next_zero_bit	find_next_zero_bit_le
+#define nilfs_find_next_bit			find_next_bit_le
 
 /**
  * struct nilfs_bh_assoc - block offset and buffer head association

fs/nilfs2/alloc.h void nilfs_palloc_setup_cache(struct inode *inode, · line 116

Quoted 10 lines
fs/nilfs2/alloc.h +5 -0
@@ -106,5 +107,10 @@ void nilfs_palloc_setup_cache(struct inode *inode,
 			      struct nilfs_palloc_cache *cache);
 void nilfs_palloc_clear_cache(struct inode *inode);
 void nilfs_palloc_destroy_cache(struct inode *inode);
+int nilfs_palloc_scan_entries(struct inode *,
+			      void (*dofunc)(struct inode *,
+					     struct nilfs_palloc_req *,
+					     void *),
+			      void *);
 
 #endif	/* _NILFS_ALLOC_H */

--
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

#5 lore raw

Re: [PATCH 1/6] nilfs2: add helper function to go through all entries of meta data file

Quoted 47 lines · Vyacheslav Dubeyko
Quoted 46 lines · Andreas Rohner

This patch introduces the nilfs_palloc_scan_entries() function, which takes an inode of one of nilfs' meta data files and iterates through all of its entries. For each entry the callback function pointer that is given as a parameter is called. The data parameter is passed to the callback function, so that it may receive parameters and return results.

---
 fs/nilfs2/alloc.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/alloc.h |   6 +++
 2 files changed, 127 insertions(+)
fs/nilfs2/alloc.c +25 -0
index 741fd02..0edd85a 100644
@@ -545,6 +545,127 @@ int nilfs_palloc_prepare_alloc_entry(struct inode *inode,
 }
 
 /**
+ * nilfs_palloc_scan_entries - scan through every entry and execute dofunc
+ * @inode: inode of metadata file using this allocator
+ * @dofunc: function executed for every entry
+ * @data: data pointer passed to dofunc
+ *
+ * Description: nilfs_palloc_scan_entries() walks through every allocated entry
+ * of a metadata file and executes dofunc on it. It passes a data pointer to
+ * dofunc, which can be used as an input parameter or for returning of results.
+ *
+ * Return Value: On success, 0 is returned. On error, a
+ * negative error code is returned.
+ */
+int nilfs_palloc_scan_entries(struct inode *inode,
+			      void (*dofunc)(struct inode *,
+					     struct nilfs_palloc_req *,
+					     void *),
+			      void *data)
+{
+	struct buffer_head *desc_bh, *bitmap_bh;
+	struct nilfs_palloc_group_desc *desc;
+	struct nilfs_palloc_req req;
+	unsigned char *bitmap;
+	void *desc_kaddr, *bitmap_kaddr;
+	unsigned long group, maxgroup, ngroups;
+	unsigned long n, m, entries_per_group, groups_per_desc_block;
Quoted 8 lines

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 576

Quoted 4 lines
fs/nilfs2/alloc.c +4 -0
+	unsigned long i, j, pos;
+	unsigned long blkoff, prev_blkoff;
+	int ret;
+

I think that it really makes sense to split this function's code between several small functions. It improves code style and readability of function. Moreover, it makes function more easy understandable.

Ok I could move one of the inner for-loops into a separate function.

Quoted 10 lines

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 584

Quoted 8 lines
fs/nilfs2/alloc.c +8 -0
+	ngroups = nilfs_palloc_groups_count(inode);
+	maxgroup = ngroups - 1;
+	entries_per_group = nilfs_palloc_entries_per_group(inode);
+	groups_per_desc_block = nilfs_palloc_groups_per_desc_block(inode);
+
+	for (group = 0; group < ngroups;) {
+		ret = nilfs_palloc_get_desc_block(inode, group, 0, &desc_bh);
+		if (ret == -ENOENT)

I suggest to add comment here.

Ok.

-ENOENT basically means, that the description block is not allocated yet, which is not an error. ngroups is a very big constant value and does not contain the actual number of groups, but rather the maximum number of groups. So the only way to tell if it is the last group is by -ENOENT error.

Quoted 33 lines
Quoted 4 lines
fs/nilfs2/alloc.c +4 -0
+			return 0;
+		else if (ret < 0)
+			return ret;
+		req.pr_desc_bh = desc_bh;

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 598

Quoted 10 lines
fs/nilfs2/alloc.c +10 -0
+		desc_kaddr = kmap(desc_bh->b_page);
+		desc = nilfs_palloc_block_get_group_desc(inode, group,
+							 desc_bh, desc_kaddr);
+		n = nilfs_palloc_rest_groups_in_desc_block(inode, group,
+							   maxgroup);
+
+		for (i = 0; i < n; i++, desc++, group++) {
+			m = entries_per_group -
+					nilfs_palloc_group_desc_nfrees(inode,
+							group, desc);

Looks weird. It makes sense to split on several functions or to use variable.

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 603

Quoted 5 lines
fs/nilfs2/alloc.c +5 -0
+			if (!m)
+				continue;
+
+			ret = nilfs_palloc_get_bitmap_block(
+				inode, group, 0, &bitmap_bh);

Ditto. Looks weird.

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 606

Quoted 3 lines
fs/nilfs2/alloc.c +3 -0
+			if (ret == -ENOENT) {
+				ret = 0;
+				goto out_desc;

It needs to add comment here. Otherwise, it looks weird because anyway we go to out_desc. Maybe to combine:

Quoted 7 lines
if (unlikely(ret < 0)) {
	if (ret == -ENOENT)
		ret = 0;
	goto out_desc;
}

Anyway, it needs to comment why we assign zero for the case of -ENOENT.

Hmm in this case -ENOENT should be considered an error. If m > 0 then nilfs_palloc_get_bitmap_block() should not return -ENOENT.

Quoted 27 lines
Quoted 27 lines
fs/nilfs2/alloc.c +27 -0
+			} else if (ret < 0)
+				goto out_desc;
+
+			req.pr_bitmap_bh = bitmap_bh;
+			bitmap_kaddr = kmap(bitmap_bh->b_page);
+			bitmap = bitmap_kaddr + bh_offset(bitmap_bh);
+			/* entry blkoff is always bigger than 0 */
+			blkoff = 0;
+			pos = 0;
+
+			for (j = 0; j < m; ++j, ++pos) {
+				pos = nilfs_find_next_bit(bitmap,
+						entries_per_group, pos);
+
+				if (pos >= entries_per_group)
+					break;
+
+				/* found an entry */
+				req.pr_entry_nr =
+					entries_per_group * group + pos;
+
+				prev_blkoff = blkoff;
+				blkoff = nilfs_palloc_entry_blkoff(inode,
+							req.pr_entry_nr);
+
+				if (blkoff != prev_blkoff) {
+					if (prev_blkoff)
Quoted 8 lines

fs/nilfs2/alloc.c int nilfs_palloc_prepare_alloc_entry(struct inode *inode, · line 638

Quoted 5 lines
fs/nilfs2/alloc.c +5 -0
+						brelse(req.pr_entry_bh);
+
+					ret = nilfs_palloc_get_entry_block(
+							inode, req.pr_entry_nr,
+							0, &req.pr_entry_bh);

Ahhhh. Look weird. :) Split on small functions with clear names, anyway. It really improves the code from any point of view.

Ok.

Quoted 58 lines

Thanks,
Vyacheslav Dubeyko.

Quoted 55 lines
fs/nilfs2/alloc.c +30 -0
+					if (ret < 0)
+						goto out_entry;
+				}
+
+				dofunc(inode, &req, data);
+			}
+
+			if (blkoff)
+				brelse(req.pr_entry_bh);
+			kunmap(bitmap_bh->b_page);
+			brelse(bitmap_bh);
+		}
+
+		kunmap(desc_bh->b_page);
+		brelse(desc_bh);
+	}
+
+	return 0;
+
+out_entry:
+	kunmap(bitmap_bh->b_page);
+	brelse(bitmap_bh);
+
+out_desc:
+	kunmap(desc_bh->b_page);
+	brelse(desc_bh);
+	return ret;
+}
+
+/**
  * nilfs_palloc_commit_alloc_entry - finish allocation of a persistent object
  * @inode: inode of metadata file using this allocator
  * @req: nilfs_palloc_req structure exchanged for the allocation
fs/nilfs2/alloc.h +6 -0
index 4bd6451..0592035 100644
@@ -77,6 +77,7 @@ int nilfs_palloc_freev(struct inode *, __u64 *, size_t);
 #define nilfs_set_bit_atomic		ext2_set_bit_atomic
 #define nilfs_clear_bit_atomic		ext2_clear_bit_atomic
 #define nilfs_find_next_zero_bit	find_next_zero_bit_le
+#define nilfs_find_next_bit			find_next_bit_le
 
 /**
  * struct nilfs_bh_assoc - block offset and buffer head association
@@ -106,5 +107,10 @@ void nilfs_palloc_setup_cache(struct inode *inode,
 			      struct nilfs_palloc_cache *cache);
 void nilfs_palloc_clear_cache(struct inode *inode);
 void nilfs_palloc_destroy_cache(struct inode *inode);
+int nilfs_palloc_scan_entries(struct inode *,
+			      void (*dofunc)(struct inode *,
+					     struct nilfs_palloc_req *,
+					     void *),
+			      void *);
 
Quoted 4 lines

fs/nilfs2/alloc.h void nilfs_palloc_setup_cache(struct inode *inode, · line 116

Quoted 1 line
fs/nilfs2/alloc.h +0 -0
 #endif	/* _NILFS_ALLOC_H */

--
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

#6 lore raw

PATCH 2/6 nilfs2: add new timestamp to seg usage and function to change su_nblocks

In reply to a message not in the archive

This patch adds an additional timestamp to the segment usage information that indicates the last time the usage information was changed. So su_lastmod indicates the last time the segment itself was modified and su_lastdec indicates the last time the usage information itself was changed.

This is important information for the GC, because it needs to avoid selecting segments for cleaning that are created (su_lastmod) outside of the protection period, but the blocks got reclaimable (su_nblocks is decremented) within the protection period. Without that information the GC policy has to assume, that there are reclaimble blocks, only to find out, that they are protected by the protection period.

This patch also introduces nilfs_sufile_add_segment_usage(), which can be used to increment or decrement the value of su_nblocks of a specific segment.

---
 fs/nilfs2/sufile.c        | 86 +++++++++++++++++++++++++++++++++++++++++++++--
 fs/nilfs2/sufile.h        | 18 ++++++++++
 include/linux/nilfs2_fs.h |  7 ++++
 3 files changed, 109 insertions(+), 2 deletions(-)
fs/nilfs2/sufile.c +84 -2
index 2a869c3..0886938 100644
@@ -453,6 +453,8 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
+	if (nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
@@ -482,7 +484,7 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
 	WARN_ON(!nilfs_segment_usage_dirty(su));
 
 	sudirty = nilfs_segment_usage_dirty(su);
-	nilfs_segment_usage_set_clean(su);
+	nilfs_sufile_segment_usage_set_clean(sufile, su);
 	kunmap_atomic(kaddr);
 	mark_buffer_dirty(su_bh);
 
@@ -549,6 +551,75 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 }
 
 /**
+ * nilfs_sufile_add_segment_usage - decrement usage of a segment
+ * @sufile: inode of segment usage file
+ * @segnum: segment number
+ * @value: value to add to su_nblocks
+ * @dectime: current time
+ *
+ * Description: nilfs_sufile_add_segment_usage() adds a signed value to the
+ * su_nblocks field of the segment usage information of @segnum. It ensures
+ * that the result is bigger than 0 and smaller or equal to the maximum number
+ * of blocks per segment
+ *
+ * Return Value: On success, 0 is returned. On error, one of the following
+ * negative error codes is returned.
+ *
+ * %-ENOMEM - Insufficient memory available.
+ *
+ * %-EIO - I/O error
+ *
+ * %-ENOENT - the specified block does not exist (hole block)
+ */
+int nilfs_sufile_add_segment_usage(struct inode *sufile, __u64 segnum,
+				   __s64 value, time_t dectime)
+{
+	struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
+	struct buffer_head *bh;
+	struct nilfs_segment_usage *su;
+	void *kaddr;
+	int ret;
+
+	if (value == 0)
+		return 0;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+
+	ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
+	if (ret < 0)
+		goto out_sem;
+
+	kaddr = kmap_atomic(bh->b_page);
+	su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
+	WARN_ON(nilfs_segment_usage_error(su));
+
+	value += le32_to_cpu(su->su_nblocks);
+	if (value < 0)
+		value = 0;
+	if (value > nilfs->ns_blocks_per_segment)
+		value = nilfs->ns_blocks_per_segment;
+
+	if (value == le32_to_cpu(su->su_nblocks)) {
+		kunmap_atomic(kaddr);
+		goto out_brelse;
+	}
+
+	su->su_nblocks = cpu_to_le32(value);
+	if (dectime && nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(dectime);
+	kunmap_atomic(kaddr);
+
+	mark_buffer_dirty(bh);
+	nilfs_mdt_mark_dirty(sufile);
+
+out_brelse:
+	brelse(bh);
+out_sem:
+	up_write(&NILFS_MDT(sufile)->mi_sem);
+	return ret;
+}
+
+/**
  * nilfs_sufile_get_stat - get segment usage statistics
  * @sufile: inode of segment usage file
  * @stat: pointer to a structure of segment usage statistics
@@ -698,7 +769,8 @@ static int nilfs_sufile_truncate_range(struct inode *sufile,
 		nc = 0;
 		for (su = su2, j = 0; j < n; j++, su = (void *)su + susz) {
 			if (nilfs_segment_usage_error(su)) {
-				nilfs_segment_usage_set_clean(su);
+				nilfs_sufile_segment_usage_set_clean(sufile,
+						su);
 				nc++;
 			}
 		}
@@ -858,6 +930,13 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 			if (nilfs_segment_is_active(nilfs, segnum + j))
 				si->sui_flags |=
 					(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+			if (sisz >= sizeof(struct nilfs_suinfo)) {
+				if (susz >= sizeof(struct nilfs_segment_usage))
+					si->sui_lastdec =
+						le64_to_cpu(su->su_lastdec);
+				else
+					si->sui_lastdec = 0;
+			}
 		}
 		kunmap_atomic(kaddr);
 		brelse(su_bh);
@@ -935,6 +1014,9 @@ ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
 		if (nilfs_suinfo_update_lastmod(sup))
 			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
 
+		if (nilfs_suinfo_update_lastdec(sup))
+			su->su_lastdec = cpu_to_le64(sup->sup_sui.sui_lastdec);
+
 		if (nilfs_suinfo_update_nblocks(sup))
 			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
 
fs/nilfs2/sufile.h +18 -0
index b8afd72..e5455d2 100644
@@ -28,6 +28,23 @@
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 
+static inline int
+nilfs_sufile_lastdec_supported(const struct inode *sufile)
+{
+	return NILFS_MDT(sufile)->mi_entry_size ==
+			sizeof(struct nilfs_segment_usage);
+}
+
+static inline void
+nilfs_sufile_segment_usage_set_clean(const struct inode *sufile,
+		struct nilfs_segment_usage *su)
+{
+	su->su_lastmod = cpu_to_le64(0);
+	su->su_nblocks = cpu_to_le32(0);
+	su->su_flags = cpu_to_le32(0);
+	if (nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(0);
+}
 
 static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile)
 {
@@ -41,6 +58,7 @@ int nilfs_sufile_alloc(struct inode *, __u64 *);
 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum);
 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 				   unsigned long nblocks, time_t modtime);
+int nilfs_sufile_add_segment_usage(struct inode *, __u64, __s64, time_t);
 int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
 ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
 				size_t);
include/linux/nilfs2_fs.h +7 -0
index ff3fea3..ca269ad 100644
@@ -614,11 +614,13 @@ struct nilfs_cpfile_header {
  * @su_lastmod: last modified timestamp
  * @su_nblocks: number of blocks in segment
  * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
  */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;
 };
 
 #define NILFS_MIN_SEGMENT_USAGE_SIZE	16
@@ -663,6 +665,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(0);
+	su->su_lastdec = cpu_to_le64(0);
 }
 
 static inline int
@@ -694,11 +697,13 @@ struct nilfs_sufile_header {
  * @sui_lastmod: timestamp of last modification
  * @sui_nblocks: number of written blocks in segment
  * @sui_flags: segment usage flags
+ * @sui_lastdec: last decrement of sui_nblocks timestamp
  */
 struct nilfs_suinfo {
 	__u64 sui_lastmod;
 	__u32 sui_nblocks;
 	__u32 sui_flags;
+	__u64 sui_lastdec;
 };
 
 #define NILFS_SUINFO_FNS(flag, name)					\
@@ -736,6 +741,7 @@ enum {
 	NILFS_SUINFO_UPDATE_LASTMOD,
 	NILFS_SUINFO_UPDATE_NBLOCKS,
 	NILFS_SUINFO_UPDATE_FLAGS,
+	NILFS_SUINFO_UPDATE_LASTDEC,
 	__NR_NILFS_SUINFO_UPDATE_FIELDS,
 };
 
@@ -759,6 +765,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
 NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
 NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
 NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec)
 
 enum {
 	NILFS_CHECKPOINT,
Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): 12561ce5e2cf8ae07fdda05e16c357f37d17c62f.1394966729.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#8 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

Quoted 6 lines · Andreas Rohner

This patch adds an additional timestamp to the segment usage information that indicates the last time the usage information was changed. So su_lastmod indicates the last time the segment itself was modified and su_lastdec indicates the last time the usage information itself was changed.

What will we have if user changes time?
What sequence will we have after such "malicious" action? Did you test such situation?

Quoted 41 lines

This is important information for the GC, because it needs to avoid selecting segments for cleaning that are created (su_lastmod) outside of the protection period, but the blocks got reclaimable (su_nblocks is decremented) within the protection period. Without that information the GC policy has to assume, that there are reclaimble blocks, only to find out, that they are protected by the protection period.

This patch also introduces nilfs_sufile_add_segment_usage(), which can be used to increment or decrement the value of su_nblocks of a specific segment.

---

fs/nilfs2/sufile.c        | 86 +++++++++++++++++++++++++++++++++++++++++++++--
fs/nilfs2/sufile.h        | 18 ++++++++++
include/linux/nilfs2_fs.h |  7 ++++
3 files changed, 109 insertions(+), 2 deletions(-)
fs/nilfs2/sufile.c +3 -1
index 2a869c3..0886938 100644
@@ -453,6 +453,8 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
+	if (nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
@@ -482,7 +484,7 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
 	WARN_ON(!nilfs_segment_usage_dirty(su));
 
 	sudirty = nilfs_segment_usage_dirty(su);
-	nilfs_segment_usage_set_clean(su);
+	nilfs_sufile_segment_usage_set_clean(sufile, su);
 	kunmap_atomic(kaddr);
 	mark_buffer_dirty(su_bh);
 

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 554

Quoted 4 lines
fs/nilfs2/sufile.c +1 -0
@@ -549,6 +551,75 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 }
 
 /**
+ * nilfs_sufile_add_segment_usage - decrement usage of a segment

I feel cultural dissonance about this name. Add or decrement? :) Decrement and add are different operations for me.

Quoted 25 lines
fs/nilfs2/sufile.c +25 -0
+ * @sufile: inode of segment usage file
+ * @segnum: segment number
+ * @value: value to add to su_nblocks
+ * @dectime: current time
+ *
+ * Description: nilfs_sufile_add_segment_usage() adds a signed value to the
+ * su_nblocks field of the segment usage information of @segnum. It ensures
+ * that the result is bigger than 0 and smaller or equal to the maximum number
+ * of blocks per segment
+ *
+ * Return Value: On success, 0 is returned. On error, one of the following
+ * negative error codes is returned.
+ *
+ * %-ENOMEM - Insufficient memory available.
+ *
+ * %-EIO - I/O error
+ *
+ * %-ENOENT - the specified block does not exist (hole block)
+ */
+int nilfs_sufile_add_segment_usage(struct inode *sufile, __u64 segnum,
+				   __s64 value, time_t dectime)
+{
+	struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
+	struct buffer_head *bh;
+	struct nilfs_segment_usage *su;

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 589

Quoted 10 lines
fs/nilfs2/sufile.c +10 -0
+	void *kaddr;
+	int ret;
+
+	if (value == 0)
+		return 0;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+
+	ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
+	if (ret < 0)

Maybe it needs to use unlikely() here.

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 596

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+		goto out_sem;
+
+	kaddr = kmap_atomic(bh->b_page);
+	su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
+	WARN_ON(nilfs_segment_usage_error(su));
+
+	value += le32_to_cpu(su->su_nblocks);

Decrement. Really? :)

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 599

Quoted 3 lines
fs/nilfs2/sufile.c +3 -0
+	if (value < 0)
+		value = 0;
+	if (value > nilfs->ns_blocks_per_segment)

maybe "else if" here?

Quoted 37 lines
fs/nilfs2/sufile.c +25 -1
+		value = nilfs->ns_blocks_per_segment;
+
+	if (value == le32_to_cpu(su->su_nblocks)) {
+		kunmap_atomic(kaddr);
+		goto out_brelse;
+	}
+
+	su->su_nblocks = cpu_to_le32(value);
+	if (dectime && nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(dectime);
+	kunmap_atomic(kaddr);
+
+	mark_buffer_dirty(bh);
+	nilfs_mdt_mark_dirty(sufile);
+
+out_brelse:
+	brelse(bh);
+out_sem:
+	up_write(&NILFS_MDT(sufile)->mi_sem);
+	return ret;
+}
+
+/**
 * nilfs_sufile_get_stat - get segment usage statistics
 * @sufile: inode of segment usage file
 * @stat: pointer to a structure of segment usage statistics
@@ -698,7 +769,8 @@ static int nilfs_sufile_truncate_range(struct inode *sufile,
 		nc = 0;
 		for (su = su2, j = 0; j < n; j++, su = (void *)su + susz) {
 			if (nilfs_segment_usage_error(su)) {
-				nilfs_segment_usage_set_clean(su);
+				nilfs_sufile_segment_usage_set_clean(sufile,
+						su);
 				nc++;
 			}
 		}

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 936

Quoted 7 lines
fs/nilfs2/sufile.c +4 -0
@@ -858,6 +930,13 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 			if (nilfs_segment_is_active(nilfs, segnum + j))
 				si->sui_flags |=
 					(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+			if (sisz >= sizeof(struct nilfs_suinfo)) {
+				if (susz >= sizeof(struct nilfs_segment_usage))
+					si->sui_lastdec =
+						le64_to_cpu(su->su_lastdec);

Is it really impossible to place assignment on one line?

Quoted 57 lines
fs/nilfs2/sufile.c +6 -0
+				else
+					si->sui_lastdec = 0;
+			}
 		}
 		kunmap_atomic(kaddr);
 		brelse(su_bh);
@@ -935,6 +1014,9 @@ ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
 		if (nilfs_suinfo_update_lastmod(sup))
 			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
 
+		if (nilfs_suinfo_update_lastdec(sup))
+			su->su_lastdec = cpu_to_le64(sup->sup_sui.sui_lastdec);
+
 		if (nilfs_suinfo_update_nblocks(sup))
 			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
 
fs/nilfs2/sufile.h +18 -0
index b8afd72..e5455d2 100644
@@ -28,6 +28,23 @@
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 
+static inline int
+nilfs_sufile_lastdec_supported(const struct inode *sufile)
+{
+	return NILFS_MDT(sufile)->mi_entry_size ==
+			sizeof(struct nilfs_segment_usage);
+}
+
+static inline void
+nilfs_sufile_segment_usage_set_clean(const struct inode *sufile,
+		struct nilfs_segment_usage *su)
+{
+	su->su_lastmod = cpu_to_le64(0);
+	su->su_nblocks = cpu_to_le32(0);
+	su->su_flags = cpu_to_le32(0);
+	if (nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(0);
+}
 
 static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile)
 {
@@ -41,6 +58,7 @@ int nilfs_sufile_alloc(struct inode *, __u64 *);
 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum);
 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 				   unsigned long nblocks, time_t modtime);
+int nilfs_sufile_add_segment_usage(struct inode *, __u64, __s64, time_t);
 int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
 ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
 				size_t);
include/linux/nilfs2_fs.h +0 -0
index ff3fea3..ca269ad 100644

include/linux/nilfs2_fs.h struct nilfs_cpfile_header { · line 623

Quoted 10 lines
include/linux/nilfs2_fs.h +2 -0
@@ -614,11 +614,13 @@ struct nilfs_cpfile_header {
 * @su_lastmod: last modified timestamp
 * @su_nblocks: number of blocks in segment
 * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
 */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;

So, this change makes on-disk layout incompatible with previous one. Am I correct? At first it needs to be fully confident that we really need in changing in this place. Secondly, it needs to add incompatible flag for s_feature_incompat field of superblock and maybe mount option.

The su_lastdec sounds not very good for my taste.

Thanks,
Vyacheslav Dubeyko.

Quoted 48 lines
include/linux/nilfs2_fs.h +1 -0
 };
 
 #define NILFS_MIN_SEGMENT_USAGE_SIZE	16
@@ -663,6 +665,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(0);
+	su->su_lastdec = cpu_to_le64(0);
 }
 

static inline int

include/linux/nilfs2_fs.h +4 -0
@@ -694,11 +697,13 @@ struct nilfs_sufile_header {
 * @sui_lastmod: timestamp of last modification
 * @sui_nblocks: number of written blocks in segment
 * @sui_flags: segment usage flags
+ * @sui_lastdec: last decrement of sui_nblocks timestamp
 */
 struct nilfs_suinfo {
 	__u64 sui_lastmod;
 	__u32 sui_nblocks;
 	__u32 sui_flags;
+	__u64 sui_lastdec;
 };
 
 #define NILFS_SUINFO_FNS(flag, name)					\
@@ -736,6 +741,7 @@ enum {
 	NILFS_SUINFO_UPDATE_LASTMOD,
 	NILFS_SUINFO_UPDATE_NBLOCKS,
 	NILFS_SUINFO_UPDATE_FLAGS,
+	NILFS_SUINFO_UPDATE_LASTDEC,
 	__NR_NILFS_SUINFO_UPDATE_FIELDS,
 };
 
@@ -759,6 +765,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
 NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
 NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
 NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec)
 
 enum {
 	NILFS_CHECKPOINT,
Signature · 6 lines
1.9.0

--
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

--
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

A message that is not in the archive (sent off-list or not yet received): 2FD47FE0-3468-4EF4-AAAE-4A636C640C44-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#10 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

Quoted 10 lines · Vyacheslav Dubeyko
Quoted 6 lines · Andreas Rohner

This patch adds an additional timestamp to the segment usage information that indicates the last time the usage information was changed. So su_lastmod indicates the last time the segment itself was modified and su_lastdec indicates the last time the usage information itself was changed.

Quoted 3 lines

What will we have if user changes time?
What sequence will we have after such "malicious" action? Did you test such situation?

The timestamp is just a hint for the userspace GC. If the hint is wrong the result would be that the GC is less efficient for a while. After a while it would go back to normal. You have the same problem with the already existing su_lastmod timestamp.

Quoted 40 lines
Quoted 40 lines

This is important information for the GC, because it needs to avoid selecting segments for cleaning that are created (su_lastmod) outside of the protection period, but the blocks got reclaimable (su_nblocks is decremented) within the protection period. Without that information the GC policy has to assume, that there are reclaimble blocks, only to find out, that they are protected by the protection period.

This patch also introduces nilfs_sufile_add_segment_usage(), which can be used to increment or decrement the value of su_nblocks of a specific segment.

---

fs/nilfs2/sufile.c        | 86 +++++++++++++++++++++++++++++++++++++++++++++--
fs/nilfs2/sufile.h        | 18 ++++++++++
include/linux/nilfs2_fs.h |  7 ++++
3 files changed, 109 insertions(+), 2 deletions(-)
fs/nilfs2/sufile.c +3 -1
index 2a869c3..0886938 100644
@@ -453,6 +453,8 @@ void nilfs_sufile_do_scrap(struct inode *sufile, __u64 segnum,
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(1UL << NILFS_SEGMENT_USAGE_DIRTY);
+	if (nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_sufile_mod_counter(header_bh, clean ? (u64)-1 : 0, dirty ? 0 : 1);
@@ -482,7 +484,7 @@ void nilfs_sufile_do_free(struct inode *sufile, __u64 segnum,
 	WARN_ON(!nilfs_segment_usage_dirty(su));
 
 	sudirty = nilfs_segment_usage_dirty(su);
-	nilfs_segment_usage_set_clean(su);
+	nilfs_sufile_segment_usage_set_clean(sufile, su);
 	kunmap_atomic(kaddr);
 	mark_buffer_dirty(su_bh);
 
Quoted 8 lines

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 554

Quoted 5 lines
fs/nilfs2/sufile.c +1 -0
@@ -549,6 +551,75 @@ int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 }
 
 /**
+ * nilfs_sufile_add_segment_usage - decrement usage of a segment

I feel cultural dissonance about this name. Add or decrement? :) Decrement and add are different operations for me.

Yes that description is wrong. Thanks for pointing that out. The long description below is correct though. By adding a signed value, one can decrement and increment.

Quoted 29 lines
Quoted 29 lines
fs/nilfs2/sufile.c +29 -0
+ * @sufile: inode of segment usage file
+ * @segnum: segment number
+ * @value: value to add to su_nblocks
+ * @dectime: current time
+ *
+ * Description: nilfs_sufile_add_segment_usage() adds a signed value to the
+ * su_nblocks field of the segment usage information of @segnum. It ensures
+ * that the result is bigger than 0 and smaller or equal to the maximum number
+ * of blocks per segment
+ *
+ * Return Value: On success, 0 is returned. On error, one of the following
+ * negative error codes is returned.
+ *
+ * %-ENOMEM - Insufficient memory available.
+ *
+ * %-EIO - I/O error
+ *
+ * %-ENOENT - the specified block does not exist (hole block)
+ */
+int nilfs_sufile_add_segment_usage(struct inode *sufile, __u64 segnum,
+				   __s64 value, time_t dectime)
+{
+	struct the_nilfs *nilfs = sufile->i_sb->s_fs_info;
+	struct buffer_head *bh;
+	struct nilfs_segment_usage *su;
+	void *kaddr;
+	int ret;
+
+	if (value == 0)
Quoted 8 lines

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 589

Quoted 6 lines
fs/nilfs2/sufile.c +6 -0
+		return 0;
+
+	down_write(&NILFS_MDT(sufile)->mi_sem);
+
+	ret = nilfs_sufile_get_segment_usage_block(sufile, segnum, 0, &bh);
+	if (ret < 0)

Maybe it needs to use unlikely() here.

Yes good idea.

Quoted 10 lines

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 596

Quoted 7 lines
fs/nilfs2/sufile.c +7 -0
+		goto out_sem;
+
+	kaddr = kmap_atomic(bh->b_page);
+	su = nilfs_sufile_block_get_segment_usage(sufile, segnum, bh, kaddr);
+	WARN_ON(nilfs_segment_usage_error(su));
+
+	value += le32_to_cpu(su->su_nblocks);

Decrement. Really? :)

Quoted 5 lines

fs/nilfs2/sufile.c int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum, · line 599

Quoted 3 lines
fs/nilfs2/sufile.c +3 -0
+	if (value < 0)
+		value = 0;
+	if (value > nilfs->ns_blocks_per_segment)

maybe "else if" here?

Yes.

Quoted 38 lines
Quoted 38 lines
fs/nilfs2/sufile.c +25 -1
+		value = nilfs->ns_blocks_per_segment;
+
+	if (value == le32_to_cpu(su->su_nblocks)) {
+		kunmap_atomic(kaddr);
+		goto out_brelse;
+	}
+
+	su->su_nblocks = cpu_to_le32(value);
+	if (dectime && nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(dectime);
+	kunmap_atomic(kaddr);
+
+	mark_buffer_dirty(bh);
+	nilfs_mdt_mark_dirty(sufile);
+
+out_brelse:
+	brelse(bh);
+out_sem:
+	up_write(&NILFS_MDT(sufile)->mi_sem);
+	return ret;
+}
+
+/**
 * nilfs_sufile_get_stat - get segment usage statistics
 * @sufile: inode of segment usage file
 * @stat: pointer to a structure of segment usage statistics
@@ -698,7 +769,8 @@ static int nilfs_sufile_truncate_range(struct inode *sufile,
 		nc = 0;
 		for (su = su2, j = 0; j < n; j++, su = (void *)su + susz) {
 			if (nilfs_segment_usage_error(su)) {
-				nilfs_segment_usage_set_clean(su);
+				nilfs_sufile_segment_usage_set_clean(sufile,
+						su);
 				nc++;
 			}
 		}
@@ -858,6 +930,13 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf,
 			if (nilfs_segment_is_active(nilfs, segnum + j))
Quoted 8 lines

fs/nilfs2/sufile.c ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, · line 936

Quoted 6 lines
fs/nilfs2/sufile.c +4 -0
 				si->sui_flags |=
 					(1UL << NILFS_SEGMENT_USAGE_ACTIVE);
+			if (sisz >= sizeof(struct nilfs_suinfo)) {
+				if (susz >= sizeof(struct nilfs_segment_usage))
+					si->sui_lastdec =
+						le64_to_cpu(su->su_lastdec);

Is it really impossible to place assignment on one line?

Yes because it is already indented so much. I couldn't find an easy way to get rid of the indentation.

Quoted 64 lines
Quoted 64 lines
fs/nilfs2/sufile.c +6 -0
+				else
+					si->sui_lastdec = 0;
+			}
 		}
 		kunmap_atomic(kaddr);
 		brelse(su_bh);
@@ -935,6 +1014,9 @@ ssize_t nilfs_sufile_set_suinfo(struct inode *sufile, void *buf,
 		if (nilfs_suinfo_update_lastmod(sup))
 			su->su_lastmod = cpu_to_le64(sup->sup_sui.sui_lastmod);
 
+		if (nilfs_suinfo_update_lastdec(sup))
+			su->su_lastdec = cpu_to_le64(sup->sup_sui.sui_lastdec);
+
 		if (nilfs_suinfo_update_nblocks(sup))
 			su->su_nblocks = cpu_to_le32(sup->sup_sui.sui_nblocks);
 
fs/nilfs2/sufile.h +18 -0
index b8afd72..e5455d2 100644
@@ -28,6 +28,23 @@
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 
+static inline int
+nilfs_sufile_lastdec_supported(const struct inode *sufile)
+{
+	return NILFS_MDT(sufile)->mi_entry_size ==
+			sizeof(struct nilfs_segment_usage);
+}
+
+static inline void
+nilfs_sufile_segment_usage_set_clean(const struct inode *sufile,
+		struct nilfs_segment_usage *su)
+{
+	su->su_lastmod = cpu_to_le64(0);
+	su->su_nblocks = cpu_to_le32(0);
+	su->su_flags = cpu_to_le32(0);
+	if (nilfs_sufile_lastdec_supported(sufile))
+		su->su_lastdec = cpu_to_le64(0);
+}
 
 static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile)
 {
@@ -41,6 +58,7 @@ int nilfs_sufile_alloc(struct inode *, __u64 *);
 int nilfs_sufile_mark_dirty(struct inode *sufile, __u64 segnum);
 int nilfs_sufile_set_segment_usage(struct inode *sufile, __u64 segnum,
 				   unsigned long nblocks, time_t modtime);
+int nilfs_sufile_add_segment_usage(struct inode *, __u64, __s64, time_t);
 int nilfs_sufile_get_stat(struct inode *, struct nilfs_sustat *);
 ssize_t nilfs_sufile_get_suinfo(struct inode *, __u64, void *, unsigned,
 				size_t);
include/linux/nilfs2_fs.h +1 -0
index ff3fea3..ca269ad 100644
@@ -614,11 +614,13 @@ struct nilfs_cpfile_header {
 * @su_lastmod: last modified timestamp
 * @su_nblocks: number of blocks in segment
 * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
 */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
Quoted 8 lines

include/linux/nilfs2_fs.h struct nilfs_cpfile_header { · line 623

Quoted 3 lines
include/linux/nilfs2_fs.h +1 -0
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;

So, this change makes on-disk layout incompatible with previous one. Am I correct? At first it needs to be fully confident that we really need in changing in this place. Secondly, it needs to add incompatible flag for s_feature_incompat field of superblock and maybe mount option.

No it IS compatible. NILFS uses the entry sizes stored in the super block. Notice, that the code does not depend on sizeof(struct nilfs_suinfo) or sizeof(struct nilfs_segment_usage). So an old kernel can read a file system with su_lastdec and a new kernel can read an old file system without su_lastdec.

Quoted 1 line

The su_lastdec sounds not very good for my taste.

Hmm, yes I agree. It is a remnant of a previous version of my code. I will think of something better.

Thanks for your review.

br,
Andreas Rohner

Quoted 47 lines

Thanks,
Vyacheslav Dubeyko.

Quoted 44 lines
include/linux/nilfs2_fs.h +1 -0
 };
 
 #define NILFS_MIN_SEGMENT_USAGE_SIZE	16
@@ -663,6 +665,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(0);
+	su->su_lastdec = cpu_to_le64(0);
 }
 

static inline int

include/linux/nilfs2_fs.h +4 -0
@@ -694,11 +697,13 @@ struct nilfs_sufile_header {
 * @sui_lastmod: timestamp of last modification
 * @sui_nblocks: number of written blocks in segment
 * @sui_flags: segment usage flags
+ * @sui_lastdec: last decrement of sui_nblocks timestamp
 */
 struct nilfs_suinfo {
 	__u64 sui_lastmod;
 	__u32 sui_nblocks;
 	__u32 sui_flags;
+	__u64 sui_lastdec;
 };
 
 #define NILFS_SUINFO_FNS(flag, name)					\
@@ -736,6 +741,7 @@ enum {
 	NILFS_SUINFO_UPDATE_LASTMOD,
 	NILFS_SUINFO_UPDATE_NBLOCKS,
 	NILFS_SUINFO_UPDATE_FLAGS,
+	NILFS_SUINFO_UPDATE_LASTDEC,
 	__NR_NILFS_SUINFO_UPDATE_FIELDS,
 };
 
@@ -759,6 +765,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
 NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
 NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
 NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec)
 
 enum {
 	NILFS_CHECKPOINT,
Signature · 1 line
1.9.0
Quoted 6 lines
Quoted 4 lines

--
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

--
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

A message that is not in the archive (sent off-list or not yet received): [email protected]

#12 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

Quoted 22 lines · Andreas Rohner
Quoted 13 lines
Quoted 13 lines
include/linux/nilfs2_fs.h +1 -0
index ff3fea3..ca269ad 100644
@@ -614,11 +614,13 @@ struct nilfs_cpfile_header {
 * @su_lastmod: last modified timestamp
 * @su_nblocks: number of blocks in segment
 * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
 */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
Quoted 8 lines

include/linux/nilfs2_fs.h struct nilfs_cpfile_header { · line 623

Quoted 3 lines
include/linux/nilfs2_fs.h +1 -0
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;

So, this change makes on-disk layout incompatible with previous one. Am I correct? At first it needs to be fully confident that we really need in changing in this place. Secondly, it needs to add incompatible flag for s_feature_incompat field of superblock and maybe mount option.

Quoted 5 lines

No it IS compatible. NILFS uses the entry sizes stored in the super block. Notice, that the code does not depend on sizeof(struct nilfs_suinfo) or sizeof(struct nilfs_segment_usage). So an old kernel can read a file system with su_lastdec and a new kernel can read an old file system without su_lastdec.

But, anyway, I think that you add some new feature by this and previous patches. I suppose that it makes sense to add specially dedicated flag or flags in s_feature_xxx field of superblock. If feature is compatible with previous state of driver then flag can be added for s_feature_compat field.

Thanks,
Vyacheslav Dubeyko.

--
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

A message that is not in the archive (sent off-list or not yet received): ED41900C-6380-44C1-AC7E-EB8DF74EBFBD-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#14 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

Quoted 31 lines · Vyacheslav Dubeyko
Quoted 22 lines · Andreas Rohner
Quoted 13 lines
Quoted 13 lines
include/linux/nilfs2_fs.h +1 -0
index ff3fea3..ca269ad 100644
@@ -614,11 +614,13 @@ struct nilfs_cpfile_header {
 * @su_lastmod: last modified timestamp
 * @su_nblocks: number of blocks in segment
 * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
 */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
Quoted 8 lines

include/linux/nilfs2_fs.h struct nilfs_cpfile_header { · line 623

Quoted 3 lines
include/linux/nilfs2_fs.h +1 -0
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;

So, this change makes on-disk layout incompatible with previous one. Am I correct? At first it needs to be fully confident that we really need in changing in this place. Secondly, it needs to add incompatible flag for s_feature_incompat field of superblock and maybe mount option.

Quoted 5 lines

No it IS compatible. NILFS uses the entry sizes stored in the super block. Notice, that the code does not depend on sizeof(struct nilfs_suinfo) or sizeof(struct nilfs_segment_usage). So an old kernel can read a file system with su_lastdec and a new kernel can read an old file system without su_lastdec.

Quoted 8 lines

But, anyway, I think that you add some new feature by this and previous patches. I suppose that it makes sense to add specially dedicated flag or flags in s_feature_xxx field of superblock. If feature is compatible with previous state of driver then flag can be added for s_feature_compat field.

Thanks,
Vyacheslav Dubeyko.

This is important thing. Please evaluate backward compatibility and forward compatibility of modifications, and properly add one of incompat, compat_ro, or compat flags as Vyacheslav mentioned. It will be a focal point of early stage review.

Regards,
Ryusuke Konishi
--
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

A message that is not in the archive (sent off-list or not yet received): 20140316.223111.52181167.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#16 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

Quoted 38 lines · Ryusuke Konishi
Quoted 37 lines · Vyacheslav Dubeyko
Quoted 22 lines · Andreas Rohner
Quoted 13 lines
Quoted 13 lines
include/linux/nilfs2_fs.h +1 -0
index ff3fea3..ca269ad 100644
@@ -614,11 +614,13 @@ struct nilfs_cpfile_header {
 * @su_lastmod: last modified timestamp
 * @su_nblocks: number of blocks in segment
 * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
 */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
Quoted 8 lines

include/linux/nilfs2_fs.h struct nilfs_cpfile_header { · line 623

Quoted 3 lines
include/linux/nilfs2_fs.h +1 -0
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;

So, this change makes on-disk layout incompatible with previous one. Am I correct? At first it needs to be fully confident that we really need in changing in this place. Secondly, it needs to add incompatible flag for s_feature_incompat field of superblock and maybe mount option.

Quoted 5 lines

No it IS compatible. NILFS uses the entry sizes stored in the super block. Notice, that the code does not depend on sizeof(struct nilfs_suinfo) or sizeof(struct nilfs_segment_usage). So an old kernel can read a file system with su_lastdec and a new kernel can read an old file system without su_lastdec.

But, anyway, I think that you add some new feature by this and previous patches. I suppose that it makes sense to add specially dedicated flag or flags in s_feature_xxx field of superblock. If feature is compatible with previous state of driver then flag can be added for s_feature_compat field.

Quoted 7 lines
Quoted 2 lines

Thanks,
Vyacheslav Dubeyko.

This is important thing. Please evaluate backward compatibility and forward compatibility of modifications, and properly add one of incompat, compat_ro, or compat flags as Vyacheslav mentioned. It will be a focal point of early stage review.

Ok, I have to look into these flags.

I reuse su_nblocks to represent the number of live blocks, which gets incremented and decremented as files are deleted and snapshots created/removed. That is definitely incompatible. Is it better to set a incompat flag or should I define a new field like su_nliveblocks? With a new field it could be compatible with older drivers, but it would add another 8 bytes to the structure.

But if I understood you correctly I need to add a new feature flag in any case.

Regards,
Andreas Rohner

Quoted 7 lines

Regards,
Ryusuke Konishi
--
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

--
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

#17 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

In reply to a message not in the archive
Quoted 13 lines · Andreas Rohner
Quoted 11 lines · Vyacheslav Dubeyko
Quoted 8 lines · Andreas Rohner

This patch adds an additional timestamp to the segment usage information that indicates the last time the usage information was changed. So su_lastmod indicates the last time the segment itself was modified and su_lastdec indicates the last time the usage information itself was changed.

Quoted 9 lines
Quoted 3 lines

What will we have if user changes time?
What sequence will we have after such "malicious" action? Did you test such situation?

The timestamp is just a hint for the userspace GC. If the hint is wrong the result would be that the GC is less efficient for a while. After a while it would go back to normal. You have the same problem with the already existing su_lastmod timestamp.

But I worry about such thing. Previously, we had complains of users about different issues with timestamp policy of GC. And I had hope that namely new GC policies can resolve such GC disadvantage. So, what have we again? The same issue of GC?

Thanks,
Vyacheslav Dubeyko.

--
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

A message that is not in the archive (sent off-list or not yet received): 0ED0D5DA-9AE9-44B8-8936-1680DE2B64C5-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#19 lore raw

Re: [PATCH 2/6] nilfs2: add new timestamp to seg usage and function to change su_nblocks

Quoted 23 lines · Vyacheslav Dubeyko
Quoted 13 lines · Andreas Rohner
Quoted 11 lines · Vyacheslav Dubeyko
Quoted 8 lines · Andreas Rohner

This patch adds an additional timestamp to the segment usage information that indicates the last time the usage information was changed. So su_lastmod indicates the last time the segment itself was modified and su_lastdec indicates the last time the usage information itself was changed.

Quoted 9 lines
Quoted 3 lines

What will we have if user changes time?
What sequence will we have after such "malicious" action? Did you test such situation?

The timestamp is just a hint for the userspace GC. If the hint is wrong the result would be that the GC is less efficient for a while. After a while it would go back to normal. You have the same problem with the already existing su_lastmod timestamp.

Quoted 4 lines

But I worry about such thing. Previously, we had complains of users about different issues with timestamp policy of GC. And I had hope that namely new GC policies can resolve such GC disadvantage. So, what have we again? The same issue of GC?

Yes but I have to compare it to the protection period, which is a timestamp. Maybe I could use the current checkpoint number instead...

Regards,
Andreas Rohner

Quoted 8 lines

Thanks,
Vyacheslav Dubeyko.

--
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

--
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

#20 lore raw

PATCH 3/6 nilfs2: scan dat entries at snapshot creation/deletion time

In reply to a message not in the archive

To accurately count the number of live blocks in a segment, it is important to take snapshots into account, because snapshots can protect reclaimable blocks from being cleaned.

This patch uses the previously reserved de_rsv field of the nilfs_dat_entry struct to store one of the snapshots the corresponding block belongs to. One block can belong to many snapshots, but because the snapshots are stored in a sorted linked list, it is easy to check if a block belongs to any other snapshot given the previous and the next snapshot. For example if the current snapshot (in de_ss) is being removed and neither the previous nor the next snapshot is in the range of de_start to de_end, then it is guaranteed that the block doesn't belong to any other snapshot and is reclaimable. On the other hand if lets say the previous snapshot is in the range of de_start to de_end, we simply set de_ss to the previous snapshot and the block is not reclaimable.

To implement this every DAT entry is scanned at snapshot creation/deletion time and updated if needed. To avoid too many update operations only potentially reclaimable blocks are ever updated. For example if there are some deleted files and the checkpoint to which these files belong is turned into a snapshot, then su_nblocks is incremented for these blocks, which reverses the decrement that happened when the files were deleted. If after some time this snapshot is deleted, su_nblocks is decremented again to reverse the increment at creation time.

---
 fs/nilfs2/cpfile.c        |  7 ++++
 fs/nilfs2/dat.c           | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           | 26 ++++++++++++++
 include/linux/nilfs2_fs.h |  4 +--
 4 files changed, 121 insertions(+), 2 deletions(-)
fs/nilfs2/cpfile.c +7 -0
index 0d58075..29952f5 100644
@@ -28,6 +28,7 @@
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "cpfile.h"
+#include "sufile.h"
 
 
 static inline unsigned long
@@ -584,6 +585,7 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 	struct nilfs_cpfile_header *header;
 	struct nilfs_checkpoint *cp;
 	struct nilfs_snapshot_list *list;
+	struct the_nilfs *nilfs = cpfile->i_sb->s_fs_info;
 	__u64 curr, prev;
 	unsigned long curr_blkoff, prev_blkoff;
 	void *kaddr;
@@ -681,6 +683,8 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 	mark_buffer_dirty(header_bh);
 	nilfs_mdt_mark_dirty(cpfile);
 
+	nilfs_dat_scan_inc_ss(nilfs->ns_dat, cno);
+
 	brelse(prev_bh);
 
  out_curr:
@@ -703,6 +707,7 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 	struct nilfs_cpfile_header *header;
 	struct nilfs_checkpoint *cp;
 	struct nilfs_snapshot_list *list;
+	struct the_nilfs *nilfs = cpfile->i_sb->s_fs_info;
 	__u64 next, prev;
 	void *kaddr;
 	int ret;
@@ -784,6 +789,8 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 	mark_buffer_dirty(header_bh);
 	nilfs_mdt_mark_dirty(cpfile);
 
+	nilfs_dat_scan_dec_ss(nilfs->ns_dat, cno, prev, next);
+
 	brelse(prev_bh);
 
  out_next:
fs/nilfs2/dat.c +86 -0

122 lines not on this page · raw message

fs/nilfs2/dat.h +26 -0
index cbd8e97..92a187e 100644
@@ -55,5 +55,31 @@ ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
 
 int nilfs_dat_read(struct super_block *sb, size_t entry_size,
 		   struct nilfs_inode *raw_inode, struct inode **inodep);
+void nilfs_dat_do_scan_dec(struct inode *, struct nilfs_palloc_req *, void *);
+void nilfs_dat_do_scan_inc(struct inode *, struct nilfs_palloc_req *, void *);
+
+/**
+ * nilfs_dat_scan_dec_ss - scan all dat entries for a checkpoint dec suinfo
+ * @dat: inode of dat file
+ * @cno: snapshot number
+ * @prev: previous snapshot number
+ * @next: next snapshot number
+ */
+static inline int nilfs_dat_scan_dec_ss(struct inode *dat, __u64 cno,
+					__u64 prev, __u64 next)
+{
+	__u64 data[3] = { cno, prev, next };
+	return nilfs_palloc_scan_entries(dat, nilfs_dat_do_scan_dec, data);
+}
+
+/**
+ * nilfs_dat_scan_dec_ss - scan all dat entries for a checkpoint inc suinfo
+ * @dat: inode of dat file
+ * @cno: snapshot number
+ */
+static inline int nilfs_dat_scan_inc_ss(struct inode *dat, __u64 cno)
+{
+	return nilfs_palloc_scan_entries(dat, nilfs_dat_do_scan_inc, &cno);
+}
 
 #endif	/* _NILFS_DAT_H */
include/linux/nilfs2_fs.h +2 -2
index ca269ad..ba9ebe02 100644
@@ -475,13 +475,13 @@ struct nilfs_palloc_group_desc {
  * @de_blocknr: block number
  * @de_start: start checkpoint number
  * @de_end: end checkpoint number
- * @de_rsv: reserved for future use
+ * @de_ss: one of the snapshots the block belongs to
  */
 struct nilfs_dat_entry {
 	__le64 de_blocknr;
 	__le64 de_start;
 	__le64 de_end;
-	__le64 de_rsv;
+	__le64 de_ss;
 };
 
 #define NILFS_MIN_DAT_ENTRY_SIZE	32
Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): 29dee92595249b713fff1e4903d5d76556926eec.1394966729.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#22 lore raw

Re: [PATCH 3/6] nilfs2: scan dat entries at snapshot creation/deletion time

Quoted 17 lines · Andreas Rohner

To accurately count the number of live blocks in a segment, it is important to take snapshots into account, because snapshots can protect reclaimable blocks from being cleaned.

This patch uses the previously reserved de_rsv field of the nilfs_dat_entry struct to store one of the snapshots the corresponding block belongs to. One block can belong to many snapshots, but because the snapshots are stored in a sorted linked list, it is easy to check if a block belongs to any other snapshot given the previous and the next snapshot. For example if the current snapshot (in de_ss) is being removed and neither the previous nor the next snapshot is in the range of de_start to de_end, then it is guaranteed that the block doesn't belong to any other snapshot and is reclaimable. On the other hand if lets say the previous snapshot is in the range of de_start to de_end, we simply set de_ss to the previous snapshot and the block is not reclaimable.

Quoted 2 lines

To implement this every DAT entry is scanned at snapshot creation/deletion time and updated if needed.

It is well known problem of NILFS2 that deletion is very slow operation for big files because of necessity to update DAT file (de_end: end checkpoint number). So, how your addition does affect this disadvantage?

Quoted 121 lines

To avoid too many update
operations only potentially reclaimable blocks are ever updated. For example if there are some deleted files and the checkpoint to which these files belong is turned into a snapshot, then su_nblocks is incremented for these blocks, which reverses the decrement that happened when the files were deleted. If after some time this snapshot is deleted, su_nblocks is decremented again to reverse the increment at creation time.

---
 fs/nilfs2/cpfile.c        |  7 ++++
 fs/nilfs2/dat.c           | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           | 26 ++++++++++++++
 include/linux/nilfs2_fs.h |  4 +--
 4 files changed, 121 insertions(+), 2 deletions(-)
fs/nilfs2/cpfile.c +7 -0
index 0d58075..29952f5 100644
@@ -28,6 +28,7 @@
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "cpfile.h"
+#include "sufile.h"
 
 
 static inline unsigned long
@@ -584,6 +585,7 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 	struct nilfs_cpfile_header *header;
 	struct nilfs_checkpoint *cp;
 	struct nilfs_snapshot_list *list;
+	struct the_nilfs *nilfs = cpfile->i_sb->s_fs_info;
 	__u64 curr, prev;
 	unsigned long curr_blkoff, prev_blkoff;
 	void *kaddr;
@@ -681,6 +683,8 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 	mark_buffer_dirty(header_bh);
 	nilfs_mdt_mark_dirty(cpfile);
 
+	nilfs_dat_scan_inc_ss(nilfs->ns_dat, cno);
+
 	brelse(prev_bh);
 
  out_curr:
@@ -703,6 +707,7 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 	struct nilfs_cpfile_header *header;
 	struct nilfs_checkpoint *cp;
 	struct nilfs_snapshot_list *list;
+	struct the_nilfs *nilfs = cpfile->i_sb->s_fs_info;
 	__u64 next, prev;
 	void *kaddr;
 	int ret;
@@ -784,6 +789,8 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 	mark_buffer_dirty(header_bh);
 	nilfs_mdt_mark_dirty(cpfile);
 
+	nilfs_dat_scan_dec_ss(nilfs->ns_dat, cno, prev, next);
+
 	brelse(prev_bh);
 
  out_next:
fs/nilfs2/dat.c +15 -0
index 0d5fada..89a4a5f 100644
@@ -28,6 +28,7 @@
 #include "mdt.h"
 #include "alloc.h"
 #include "dat.h"
+#include "sufile.h"
 
 
 #define NILFS_CNO_MIN	((__u64)1)
@@ -97,6 +98,7 @@ void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req)
 	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
 	entry->de_end = cpu_to_le64(NILFS_CNO_MAX);
 	entry->de_blocknr = cpu_to_le64(0);
+	entry->de_ss = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_palloc_commit_alloc_entry(dat, req);
@@ -121,6 +123,7 @@ static void nilfs_dat_commit_free(struct inode *dat,
 	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
 	entry->de_end = cpu_to_le64(NILFS_CNO_MIN);
 	entry->de_blocknr = cpu_to_le64(0);
+	entry->de_ss = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_dat_commit_entry(dat, req);
@@ -201,6 +204,7 @@ void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,
 		WARN_ON(start > end);
 	}
 	entry->de_end = cpu_to_le64(end);
+	entry->de_ss = cpu_to_le64(NILFS_CNO_MAX);
 	blocknr = le64_to_cpu(entry->de_blocknr);
 	kunmap_atomic(kaddr);
 
@@ -365,6 +369,8 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
 	}
 	WARN_ON(blocknr == 0);
 	entry->de_blocknr = cpu_to_le64(blocknr);
+	if (entry->de_ss == cpu_to_le64(NILFS_CNO_MAX))
+		entry->de_ss = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	mark_buffer_dirty(entry_bh);
@@ -430,6 +436,86 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
 	return ret;
 }
 
+void nilfs_dat_do_scan_dec(struct inode *dat, struct nilfs_palloc_req *req,
+			   void *data)
+{
+	struct nilfs_dat_entry *entry;
+	__u64 start, end, prev_ss;
+	__u64 *ssp = data, ss = ssp[0], prev = ssp[1], next = ssp[2];
+	sector_t blocknr;
+	void *kaddr;
+	struct the_nilfs *nilfs;

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 457

Quoted 10 lines
fs/nilfs2/dat.c +10 -0
+
+	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
+					     req->pr_entry_bh, kaddr);
+	start = le64_to_cpu(entry->de_start);
+	end = le64_to_cpu(entry->de_end);
+	blocknr = le64_to_cpu(entry->de_blocknr);
+	prev_ss = le64_to_cpu(entry->de_ss);
+
+	if (blocknr != 0 && end != NILFS_CNO_MAX && ss >= start && ss < end) {

I think that it makes sense to use small functions with clear names about what we check.

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 464

Quoted 7 lines
fs/nilfs2/dat.c +7 -0
+		if (prev_ss == ss || prev_ss == NILFS_CNO_MAX) {
+			if (prev && prev >= start && prev < end)
+				entry->de_ss = cpu_to_le64(prev);
+			else if (next && next >= start && next < end)
+				entry->de_ss = cpu_to_le64(next);
+			else
+				entry->de_ss = cpu_to_le64(0);

Ditto.

Quoted 29 lines
fs/nilfs2/dat.c +29 -0
+
+			if (prev_ss != NILFS_CNO_MAX)
+				prev_ss = le64_to_cpu(entry->de_ss);
+			kunmap_atomic(kaddr);
+			mark_buffer_dirty(req->pr_entry_bh);
+			nilfs_mdt_mark_dirty(dat);
+		} else
+			kunmap_atomic(kaddr);
+
+		if (prev_ss == 0) {
+			nilfs = dat->i_sb->s_fs_info;
+			nilfs_sufile_add_segment_usage(nilfs->ns_sufile,
+				nilfs_get_segnum_of_block(nilfs, blocknr),
+				-1, 0);
+		}
+	} else
+		kunmap_atomic(kaddr);
+}
+
+void nilfs_dat_do_scan_inc(struct inode *dat, struct nilfs_palloc_req *req,
+			   void *data)
+{
+	struct nilfs_dat_entry *entry;
+	__u64 start, end, prev_ss;
+	__u64 *ssp = data, ss = *ssp;
+	sector_t blocknr;
+	void *kaddr;
+	struct the_nilfs *nilfs;
+

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 503

Quoted 10 lines
fs/nilfs2/dat.c +10 -0
+	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
+			req->pr_entry_bh, kaddr);
+	start = le64_to_cpu(entry->de_start);
+	end = le64_to_cpu(entry->de_end);
+	blocknr = le64_to_cpu(entry->de_blocknr);
+	prev_ss = le64_to_cpu(entry->de_ss);
+
+	if (blocknr != 0 && end != NILFS_CNO_MAX && ss >= start && ss < end &&
+			(prev_ss == 0 || prev_ss == NILFS_CNO_MAX)) {

Ditto. Moreover, you repeat this check.

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 513

Quoted 10 lines
fs/nilfs2/dat.c +10 -0
+
+		entry->de_ss = cpu_to_le64(ss);
+
+		kunmap_atomic(kaddr);
+		mark_buffer_dirty(req->pr_entry_bh);
+		nilfs_mdt_mark_dirty(dat);
+
+		nilfs = dat->i_sb->s_fs_info;
+		nilfs_sufile_add_segment_usage(nilfs->ns_sufile,
+				nilfs_get_segnum_of_block(nilfs, blocknr),

Looks weird. Maybe, variable?

Thanks,
Vyacheslav Dubeyko.

Quoted 54 lines
fs/nilfs2/dat.c +5 -0
+				1, 0);
+	} else
+		kunmap_atomic(kaddr);
+}
+
 ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz,
 			    size_t nvi)
 {
fs/nilfs2/dat.h +26 -0
index cbd8e97..92a187e 100644
@@ -55,5 +55,31 @@ ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
 
 int nilfs_dat_read(struct super_block *sb, size_t entry_size,
 		   struct nilfs_inode *raw_inode, struct inode **inodep);
+void nilfs_dat_do_scan_dec(struct inode *, struct nilfs_palloc_req *, void *);
+void nilfs_dat_do_scan_inc(struct inode *, struct nilfs_palloc_req *, void *);
+
+/**
+ * nilfs_dat_scan_dec_ss - scan all dat entries for a checkpoint dec suinfo
+ * @dat: inode of dat file
+ * @cno: snapshot number
+ * @prev: previous snapshot number
+ * @next: next snapshot number
+ */
+static inline int nilfs_dat_scan_dec_ss(struct inode *dat, __u64 cno,
+					__u64 prev, __u64 next)
+{
+	__u64 data[3] = { cno, prev, next };
+	return nilfs_palloc_scan_entries(dat, nilfs_dat_do_scan_dec, data);
+}
+
+/**
+ * nilfs_dat_scan_dec_ss - scan all dat entries for a checkpoint inc suinfo
+ * @dat: inode of dat file
+ * @cno: snapshot number
+ */
+static inline int nilfs_dat_scan_inc_ss(struct inode *dat, __u64 cno)
+{
+	return nilfs_palloc_scan_entries(dat, nilfs_dat_do_scan_inc, &cno);
+}
 
 #endif	/* _NILFS_DAT_H */
include/linux/nilfs2_fs.h +1 -1
index ca269ad..ba9ebe02 100644
@@ -475,13 +475,13 @@ struct nilfs_palloc_group_desc {
  * @de_blocknr: block number
  * @de_start: start checkpoint number
  * @de_end: end checkpoint number
- * @de_rsv: reserved for future use
+ * @de_ss: one of the snapshots the block belongs to

include/linux/nilfs2_fs.h struct nilfs_palloc_group_desc { · line 487

Quoted 10 lines
include/linux/nilfs2_fs.h +1 -1
  */
 struct nilfs_dat_entry {
 	__le64 de_blocknr;
 	__le64 de_start;
 	__le64 de_end;
-	__le64 de_rsv;
+	__le64 de_ss;
 };
 
 #define NILFS_MIN_DAT_ENTRY_SIZE	32

--
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

#23 lore raw

Re: [PATCH 3/6] nilfs2: scan dat entries at snapshot creation/deletion time

Quoted 18 lines · Vyacheslav Dubeyko
Quoted 17 lines · Andreas Rohner

To accurately count the number of live blocks in a segment, it is important to take snapshots into account, because snapshots can protect reclaimable blocks from being cleaned.

This patch uses the previously reserved de_rsv field of the nilfs_dat_entry struct to store one of the snapshots the corresponding block belongs to. One block can belong to many snapshots, but because the snapshots are stored in a sorted linked list, it is easy to check if a block belongs to any other snapshot given the previous and the next snapshot. For example if the current snapshot (in de_ss) is being removed and neither the previous nor the next snapshot is in the range of de_start to de_end, then it is guaranteed that the block doesn't belong to any other snapshot and is reclaimable. On the other hand if lets say the previous snapshot is in the range of de_start to de_end, we simply set de_ss to the previous snapshot and the block is not reclaimable.

Quoted 6 lines
Quoted 2 lines

To implement this every DAT entry is scanned at snapshot creation/deletion time and updated if needed.

It is well known problem of NILFS2 that deletion is very slow operation for big files because of necessity to update DAT file (de_end: end checkpoint number). So, how your addition does affect this disadvantage?

Additionally to setting "de_end: end checkpoint number" the live block counter in the SUFILE needs to be decremented. This makes the deletion a little bit more expensive, but its not really noticeable, because the SUFILE-Entries are mostly in the cache. I have timed the deletion of 100 GB and there is no discernible difference in the performance.

But my additions make snapshot creation and deletion more expensive.

Quoted 126 lines
Quoted 126 lines

To avoid too many update
operations only potentially reclaimable blocks are ever updated. For example if there are some deleted files and the checkpoint to which these files belong is turned into a snapshot, then su_nblocks is incremented for these blocks, which reverses the decrement that happened when the files were deleted. If after some time this snapshot is deleted, su_nblocks is decremented again to reverse the increment at creation time.

---
 fs/nilfs2/cpfile.c        |  7 ++++
 fs/nilfs2/dat.c           | 86 +++++++++++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           | 26 ++++++++++++++
 include/linux/nilfs2_fs.h |  4 +--
 4 files changed, 121 insertions(+), 2 deletions(-)
fs/nilfs2/cpfile.c +7 -0
index 0d58075..29952f5 100644
@@ -28,6 +28,7 @@
 #include <linux/nilfs2_fs.h>
 #include "mdt.h"
 #include "cpfile.h"
+#include "sufile.h"
 
 
 static inline unsigned long
@@ -584,6 +585,7 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 	struct nilfs_cpfile_header *header;
 	struct nilfs_checkpoint *cp;
 	struct nilfs_snapshot_list *list;
+	struct the_nilfs *nilfs = cpfile->i_sb->s_fs_info;
 	__u64 curr, prev;
 	unsigned long curr_blkoff, prev_blkoff;
 	void *kaddr;
@@ -681,6 +683,8 @@ static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 	mark_buffer_dirty(header_bh);
 	nilfs_mdt_mark_dirty(cpfile);
 
+	nilfs_dat_scan_inc_ss(nilfs->ns_dat, cno);
+
 	brelse(prev_bh);
 
  out_curr:
@@ -703,6 +707,7 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 	struct nilfs_cpfile_header *header;
 	struct nilfs_checkpoint *cp;
 	struct nilfs_snapshot_list *list;
+	struct the_nilfs *nilfs = cpfile->i_sb->s_fs_info;
 	__u64 next, prev;
 	void *kaddr;
 	int ret;
@@ -784,6 +789,8 @@ static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 	mark_buffer_dirty(header_bh);
 	nilfs_mdt_mark_dirty(cpfile);
 
+	nilfs_dat_scan_dec_ss(nilfs->ns_dat, cno, prev, next);
+
 	brelse(prev_bh);
 
  out_next:
fs/nilfs2/dat.c +20 -0
index 0d5fada..89a4a5f 100644
@@ -28,6 +28,7 @@
 #include "mdt.h"
 #include "alloc.h"
 #include "dat.h"
+#include "sufile.h"
 
 
 #define NILFS_CNO_MIN	((__u64)1)
@@ -97,6 +98,7 @@ void nilfs_dat_commit_alloc(struct inode *dat, struct nilfs_palloc_req *req)
 	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
 	entry->de_end = cpu_to_le64(NILFS_CNO_MAX);
 	entry->de_blocknr = cpu_to_le64(0);
+	entry->de_ss = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_palloc_commit_alloc_entry(dat, req);
@@ -121,6 +123,7 @@ static void nilfs_dat_commit_free(struct inode *dat,
 	entry->de_start = cpu_to_le64(NILFS_CNO_MIN);
 	entry->de_end = cpu_to_le64(NILFS_CNO_MIN);
 	entry->de_blocknr = cpu_to_le64(0);
+	entry->de_ss = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	nilfs_dat_commit_entry(dat, req);
@@ -201,6 +204,7 @@ void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,
 		WARN_ON(start > end);
 	}
 	entry->de_end = cpu_to_le64(end);
+	entry->de_ss = cpu_to_le64(NILFS_CNO_MAX);
 	blocknr = le64_to_cpu(entry->de_blocknr);
 	kunmap_atomic(kaddr);
 
@@ -365,6 +369,8 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
 	}
 	WARN_ON(blocknr == 0);
 	entry->de_blocknr = cpu_to_le64(blocknr);
+	if (entry->de_ss == cpu_to_le64(NILFS_CNO_MAX))
+		entry->de_ss = cpu_to_le64(0);
 	kunmap_atomic(kaddr);
 
 	mark_buffer_dirty(entry_bh);
@@ -430,6 +436,86 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp)
 	return ret;
 }
 
+void nilfs_dat_do_scan_dec(struct inode *dat, struct nilfs_palloc_req *req,
+			   void *data)
+{
+	struct nilfs_dat_entry *entry;
+	__u64 start, end, prev_ss;
+	__u64 *ssp = data, ss = ssp[0], prev = ssp[1], next = ssp[2];
+	sector_t blocknr;
+	void *kaddr;
+	struct the_nilfs *nilfs;
+
+	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
+					     req->pr_entry_bh, kaddr);
+	start = le64_to_cpu(entry->de_start);
Quoted 8 lines

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 457

Quoted 5 lines
fs/nilfs2/dat.c +5 -0
+	end = le64_to_cpu(entry->de_end);
+	blocknr = le64_to_cpu(entry->de_blocknr);
+	prev_ss = le64_to_cpu(entry->de_ss);
+
+	if (blocknr != 0 && end != NILFS_CNO_MAX && ss >= start && ss < end) {

I think that it makes sense to use small functions with clear names about what we check.

Ok.

Quoted 43 lines

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 464

Quoted 7 lines
fs/nilfs2/dat.c +7 -0
+		if (prev_ss == ss || prev_ss == NILFS_CNO_MAX) {
+			if (prev && prev >= start && prev < end)
+				entry->de_ss = cpu_to_le64(prev);
+			else if (next && next >= start && next < end)
+				entry->de_ss = cpu_to_le64(next);
+			else
+				entry->de_ss = cpu_to_le64(0);

Ditto.

Quoted 33 lines
fs/nilfs2/dat.c +33 -0
+
+			if (prev_ss != NILFS_CNO_MAX)
+				prev_ss = le64_to_cpu(entry->de_ss);
+			kunmap_atomic(kaddr);
+			mark_buffer_dirty(req->pr_entry_bh);
+			nilfs_mdt_mark_dirty(dat);
+		} else
+			kunmap_atomic(kaddr);
+
+		if (prev_ss == 0) {
+			nilfs = dat->i_sb->s_fs_info;
+			nilfs_sufile_add_segment_usage(nilfs->ns_sufile,
+				nilfs_get_segnum_of_block(nilfs, blocknr),
+				-1, 0);
+		}
+	} else
+		kunmap_atomic(kaddr);
+}
+
+void nilfs_dat_do_scan_inc(struct inode *dat, struct nilfs_palloc_req *req,
+			   void *data)
+{
+	struct nilfs_dat_entry *entry;
+	__u64 start, end, prev_ss;
+	__u64 *ssp = data, ss = *ssp;
+	sector_t blocknr;
+	void *kaddr;
+	struct the_nilfs *nilfs;
+
+	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
+			req->pr_entry_bh, kaddr);
+	start = le64_to_cpu(entry->de_start);
Quoted 8 lines

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 503

Quoted 6 lines
fs/nilfs2/dat.c +6 -0
+	end = le64_to_cpu(entry->de_end);
+	blocknr = le64_to_cpu(entry->de_blocknr);
+	prev_ss = le64_to_cpu(entry->de_ss);
+
+	if (blocknr != 0 && end != NILFS_CNO_MAX && ss >= start && ss < end &&
+			(prev_ss == 0 || prev_ss == NILFS_CNO_MAX)) {

Ditto. Moreover, you repeat this check.

What do you mean? Where do I repeat this check?

Quoted 4 lines
Quoted 4 lines
fs/nilfs2/dat.c +4 -0
+
+		entry->de_ss = cpu_to_le64(ss);
+
+		kunmap_atomic(kaddr);
Quoted 8 lines

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 477

Quoted 6 lines
fs/nilfs2/dat.c +6 -0
+		mark_buffer_dirty(req->pr_entry_bh);
+		nilfs_mdt_mark_dirty(dat);
+
+		nilfs = dat->i_sb->s_fs_info;
+		nilfs_sufile_add_segment_usage(nilfs->ns_sufile,
+				nilfs_get_segnum_of_block(nilfs, blocknr),

Looks weird. Maybe, variable?

Ok.

Thanks for your review so far.

Best regards,
Andreas Rohner

Quoted 66 lines

Thanks,
Vyacheslav Dubeyko.

Quoted 63 lines
fs/nilfs2/dat.c +5 -0
+				1, 0);
+	} else
+		kunmap_atomic(kaddr);
+}
+
 ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz,
 			    size_t nvi)
 {
fs/nilfs2/dat.h +26 -0
index cbd8e97..92a187e 100644
@@ -55,5 +55,31 @@ ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
 
 int nilfs_dat_read(struct super_block *sb, size_t entry_size,
 		   struct nilfs_inode *raw_inode, struct inode **inodep);
+void nilfs_dat_do_scan_dec(struct inode *, struct nilfs_palloc_req *, void *);
+void nilfs_dat_do_scan_inc(struct inode *, struct nilfs_palloc_req *, void *);
+
+/**
+ * nilfs_dat_scan_dec_ss - scan all dat entries for a checkpoint dec suinfo
+ * @dat: inode of dat file
+ * @cno: snapshot number
+ * @prev: previous snapshot number
+ * @next: next snapshot number
+ */
+static inline int nilfs_dat_scan_dec_ss(struct inode *dat, __u64 cno,
+					__u64 prev, __u64 next)
+{
+	__u64 data[3] = { cno, prev, next };
+	return nilfs_palloc_scan_entries(dat, nilfs_dat_do_scan_dec, data);
+}
+
+/**
+ * nilfs_dat_scan_dec_ss - scan all dat entries for a checkpoint inc suinfo
+ * @dat: inode of dat file
+ * @cno: snapshot number
+ */
+static inline int nilfs_dat_scan_inc_ss(struct inode *dat, __u64 cno)
+{
+	return nilfs_palloc_scan_entries(dat, nilfs_dat_do_scan_inc, &cno);
+}
 
 #endif	/* _NILFS_DAT_H */
include/linux/nilfs2_fs.h +2 -2
index ca269ad..ba9ebe02 100644
@@ -475,13 +475,13 @@ struct nilfs_palloc_group_desc {
  * @de_blocknr: block number
  * @de_start: start checkpoint number
  * @de_end: end checkpoint number
- * @de_rsv: reserved for future use
+ * @de_ss: one of the snapshots the block belongs to
  */
 struct nilfs_dat_entry {
 	__le64 de_blocknr;
 	__le64 de_start;
 	__le64 de_end;
-	__le64 de_rsv;
+	__le64 de_ss;
 };
 
Quoted 8 lines

include/linux/nilfs2_fs.h struct nilfs_palloc_group_desc { · line 487

Quoted 1 line
include/linux/nilfs2_fs.h +0 -0
 #define NILFS_MIN_DAT_ENTRY_SIZE	32

--
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

--
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

A message that is not in the archive (sent off-list or not yet received): [email protected]

#25 lore raw

Re: [PATCH 3/6] nilfs2: scan dat entries at snapshot creation/deletion time

Quoted 8 lines · Andreas Rohner
Quoted 5 lines

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 503

Quoted 3 lines
fs/nilfs2/dat.c +3 -0
+
+	if (blocknr != 0 && end != NILFS_CNO_MAX && ss >= start && ss < end &&
+			(prev_ss == 0 || prev_ss == NILFS_CNO_MAX)) {

Ditto. Moreover, you repeat this check.

What do you mean? Where do I repeat this check?

I mean this check above:

Quoted 1 line

fs/nilfs2/dat.c int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) · line 457

Quoted 1 line
fs/nilfs2/dat.c +1 -0
+	if (blocknr != 0 && end != NILFS_CNO_MAX && ss >= start && ss < end) {

Thanks,
Vyacheslav Dubeyko.

--
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

#26 lore raw

PATCH 4/6 nilfs2: add ioctl() to clean snapshot flags from dat entries

In reply to a message not in the archive

This patch introduces new flags for nilfs_vdesc to indicate the reason a block is alive. So if the block would be reclaimable, but must be treated as if it were alive, because it is part of a snapshot, then the snapshot flag is set.

Additionally a new ioctl() is added, which enables the userspace GC to perform a cleanup operation after setting the number of blocks with NILFS_IOCTL_SET_SUINFO. It sets DAT entries with de_ss values of NILFS_CNO_MAX to 0. NILFS_CNO_MAX indicates, that the corresponding block belongs to some snapshot, but was already decremented by a previous deletion operation. If the segment usage info is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated, then these blocks would never be decremented and there are scenarios where the corresponding segments would starve (never be cleaned). To prevent that they must be reset to 0.

---
 fs/nilfs2/dat.c           |  63 ++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           |   1 +
 fs/nilfs2/ioctl.c         | 103 +++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/nilfs2_fs.h |  52 ++++++++++++++++++++++-
 4 files changed, 216 insertions(+), 3 deletions(-)
fs/nilfs2/dat.c +63 -0
index 89a4a5f..7adb15d 100644
@@ -382,6 +382,69 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
 }
 
 /**
+ * nilfs_dat_clean_snapshot_flag - check flags used by snapshots
+ * @dat: DAT file inode
+ * @vblocknr: virtual block number
+ *
+ * Description: nilfs_dat_clean_snapshot_flag() changes the flags from
+ * NILFS_CNO_MAX to 0 if necessary, so that segment usage is accurately
+ * counted. NILFS_CNO_MAX indicates, that the corresponding block belongs
+ * to some snapshot, but was already decremented. If the segment usage info
+ * is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated,
+ * then these blocks would never be decremented and there are scenarios where
+ * the corresponding segments would starve (never be cleaned).
+ *
+ * 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.
+ */
+int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr)
+{
+	struct buffer_head *entry_bh;
+	struct nilfs_dat_entry *entry;
+	void *kaddr;
+	int ret;
+
+	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The given disk block number (blocknr) is not yet written to
+	 * the device at this point.
+	 *
+	 * To prevent nilfs_dat_translate() from returning the
+	 * uncommitted block number, this makes a copy of the entry
+	 * buffer and redirects nilfs_dat_translate() to the copy.
+	 */
+	if (!buffer_nilfs_redirected(entry_bh)) {
+		ret = nilfs_mdt_freeze_buffer(dat, entry_bh);
+		if (ret) {
+			brelse(entry_bh);
+			return ret;
+		}
+	}
+
+	kaddr = kmap_atomic(entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
+	if (entry->de_ss == cpu_to_le64(NILFS_CNO_MAX)) {
+		entry->de_ss = cpu_to_le64(0);
+		kunmap_atomic(kaddr);
+		mark_buffer_dirty(entry_bh);
+		nilfs_mdt_mark_dirty(dat);
+	} else {
+		kunmap_atomic(kaddr);
+	}
+
+	brelse(entry_bh);
+
+	return 0;
+}
+
+/**
  * nilfs_dat_translate - translate a virtual block number to a block number
  * @dat: DAT file inode
  * @vblocknr: virtual block number
fs/nilfs2/dat.h +1 -0
index 92a187e..a528024 100644
@@ -51,6 +51,7 @@ void nilfs_dat_abort_update(struct inode *, struct nilfs_palloc_req *,
 int nilfs_dat_mark_dirty(struct inode *, __u64);
 int nilfs_dat_freev(struct inode *, __u64 *, size_t);
 int nilfs_dat_move(struct inode *, __u64, sector_t);
+int nilfs_dat_clean_snapshot_flag(struct inode *, __u64);
 ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
 
 int nilfs_dat_read(struct super_block *sb, size_t entry_size,
fs/nilfs2/ioctl.c +102 -1

133 lines not on this page · raw message

include/linux/nilfs2_fs.h +50 -2

71 lines not on this page · raw message

Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): be7d3bd13015117222aac43194c0fdb9c5d0046f.1394966729.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#28 lore raw

Re: [PATCH 4/6] nilfs2: add ioctl() to clean snapshot flags from dat entries

Quoted 5 lines · Andreas Rohner

This patch introduces new flags for nilfs_vdesc to indicate the reason a block is alive. So if the block would be reclaimable, but must be treated as if it were alive, because it is part of a snapshot, then the snapshot flag is set.

I suppose that I don't quite follow your idea. As far as I can judge, every block in DAT file has: (1) de_start: start checkpoint number; (2)
de_end: end checkpoint number. So, while one of checkpoint number is snapshot number then we know that this block lives in snapshot. Am I correct? Why do we need in special flags?

Quoted 37 lines

Additionally a new ioctl() is added, which enables the userspace GC to perform a cleanup operation after setting the number of blocks with NILFS_IOCTL_SET_SUINFO. It sets DAT entries with de_ss values of NILFS_CNO_MAX to 0. NILFS_CNO_MAX indicates, that the corresponding block belongs to some snapshot, but was already decremented by a previous deletion operation. If the segment usage info is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated, then these blocks would never be decremented and there are scenarios where the corresponding segments would starve (never be cleaned). To prevent that they must be reset to 0.

---
 fs/nilfs2/dat.c           |  63 ++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           |   1 +
 fs/nilfs2/ioctl.c         | 103 +++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/nilfs2_fs.h |  52 ++++++++++++++++++++++-
 4 files changed, 216 insertions(+), 3 deletions(-)
fs/nilfs2/dat.c +10 -0
index 89a4a5f..7adb15d 100644
@@ -382,6 +382,69 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
 }
 
 /**
+ * nilfs_dat_clean_snapshot_flag - check flags used by snapshots
+ * @dat: DAT file inode
+ * @vblocknr: virtual block number
+ *
+ * Description: nilfs_dat_clean_snapshot_flag() changes the flags from
+ * NILFS_CNO_MAX to 0 if necessary, so that segment usage is accurately
+ * counted. NILFS_CNO_MAX indicates, that the corresponding block belongs
+ * to some snapshot, but was already decremented. If the segment usage info
+ * is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated,
+ * then these blocks would never be decremented and there are scenarios where

fs/nilfs2/dat.c int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) · line 404

Quoted 10 lines
fs/nilfs2/dat.c +10 -0
+ * the corresponding segments would starve (never be cleaned).
+ *
+ * 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.
+ */
+int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr)

Sounds likewise we clear flag. It can be confusing name.

Quoted 26 lines
fs/nilfs2/dat.c +26 -0
+{
+	struct buffer_head *entry_bh;
+	struct nilfs_dat_entry *entry;
+	void *kaddr;
+	int ret;
+
+	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The given disk block number (blocknr) is not yet written to
+	 * the device at this point.
+	 *
+	 * To prevent nilfs_dat_translate() from returning the
+	 * uncommitted block number, this makes a copy of the entry
+	 * buffer and redirects nilfs_dat_translate() to the copy.
+	 */
+	if (!buffer_nilfs_redirected(entry_bh)) {
+		ret = nilfs_mdt_freeze_buffer(dat, entry_bh);
+		if (ret) {
+			brelse(entry_bh);
+			return ret;
+		}
+	}
+

fs/nilfs2/dat.c int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) · line 440

Quoted 10 lines
fs/nilfs2/dat.c +10 -0
+	kaddr = kmap_atomic(entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
+	if (entry->de_ss == cpu_to_le64(NILFS_CNO_MAX)) {
+		entry->de_ss = cpu_to_le64(0);
+		kunmap_atomic(kaddr);
+		mark_buffer_dirty(entry_bh);
+		nilfs_mdt_mark_dirty(dat);
+	} else {
+		kunmap_atomic(kaddr);
+	}

Brackets are unnecessary here.

Quoted 36 lines
fs/nilfs2/dat.c +7 -0
+
+	brelse(entry_bh);
+
+	return 0;
+}
+
+/**
  * nilfs_dat_translate - translate a virtual block number to a block number
  * @dat: DAT file inode
  * @vblocknr: virtual block number
fs/nilfs2/dat.h +1 -0
index 92a187e..a528024 100644
@@ -51,6 +51,7 @@ void nilfs_dat_abort_update(struct inode *, struct nilfs_palloc_req *,
 int nilfs_dat_mark_dirty(struct inode *, __u64);
 int nilfs_dat_freev(struct inode *, __u64 *, size_t);
 int nilfs_dat_move(struct inode *, __u64, sector_t);
+int nilfs_dat_clean_snapshot_flag(struct inode *, __u64);
 ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
 
 int nilfs_dat_read(struct super_block *sb, size_t entry_size,
fs/nilfs2/ioctl.c +1 -1
index 422fb54..0b62bf4 100644
@@ -578,7 +578,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
 	struct buffer_head *bh;
 	int ret;
 
-	if (vdesc->vd_flags == 0)
+	if (nilfs_vdesc_data(vdesc))
 		ret = nilfs_gccache_submit_read_data(
 			inode, vdesc->vd_offset, vdesc->vd_blocknr,
 			vdesc->vd_vblocknr, &bh);

fs/nilfs2/ioctl.c static int nilfs_ioctl_move_blocks(struct super_block *sb, · line 669

Quoted 8 lines
fs/nilfs2/ioctl.c +5 -0
@@ -662,6 +662,14 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb,
 		}
 
 		do {
+			/*
+			 * old user space tools to not initialize vd_flags2
+			 * check if it contains invalid flags
+			 */
+			if (vdesc->vd_flags2 &

"vd_flags2" is really bad naming. Completely obscure.

fs/nilfs2/ioctl.c static int nilfs_ioctl_move_blocks(struct super_block *sb, · line 670

Quoted 1 line
fs/nilfs2/ioctl.c +1 -0
+					(~0UL << __NR_NILFS_VDESC_FIELDS))

Looks weird.

fs/nilfs2/ioctl.c out: · line 995

Quoted 10 lines
fs/nilfs2/ioctl.c +3 -0
+				vdesc->vd_flags2 = 0;
+
 			ret = nilfs_ioctl_move_inode_block(inode, vdesc,
 							   &buffers);
 			if (unlikely(ret < 0)) {
@@ -984,6 +992,96 @@ out:
 }
 
 /**
+ * nilfs_ioctl_clean_snapshot_flags - clean dat entries with invalid de_ss

Ditto. Sounds likewise clearing of flag.

Quoted 102 lines
fs/nilfs2/ioctl.c +91 -0
+ * @inode: inode object
+ * @filp: file object
+ * @cmd: ioctl's request code
+ * @argp: pointer on argument from userspace
+ *
+ * Description: nilfs_ioctl_clean_snapshot_flags() sets DAT entries with de_ss
+ * values of NILFS_CNO_MAX to 0. NILFS_CNO_MAX indicates, that the
+ * corresponding block belongs to some snapshot, but was already decremented.
+ * If the segment usage info is changed with NILFS_IOCTL_SET_SUINFO and the
+ * number of blocks is updated, then these blocks would never be decremented
+ * and there are scenarios where the corresponding segments would starve (never
+ * be cleaned).
+ *
+ * Return Value: On success, 0 is returned or error code, otherwise.
+ */
+static int nilfs_ioctl_clean_snapshot_flags(struct inode *inode,
+					    struct file *filp,
+					    unsigned int cmd,
+					    void __user *argp)
+{
+	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+	struct nilfs_transaction_info ti;
+	struct nilfs_argv argv;
+	struct nilfs_vdesc *vdesc;
+	size_t len, i;
+	void __user *base;
+	void *kbuf;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&argv, argp, sizeof(struct nilfs_argv)))
+		goto out;
+
+	ret = -EINVAL;
+	if (argv.v_size != sizeof(struct nilfs_vdesc))
+		goto out;
+	if (argv.v_nmembs > UINT_MAX / sizeof(struct nilfs_vdesc))
+		goto out;
+
+	len = argv.v_size * argv.v_nmembs;
+	if (!len) {
+		ret = 0;
+		goto out;
+	}
+
+	base = (void __user *)(unsigned long)argv.v_base;
+	kbuf = vmalloc(len);
+	if (!kbuf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(kbuf, base, len)) {
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
+	if (unlikely(ret))
+		goto out_free;
+
+	for (i = 0, vdesc = kbuf; i < argv.v_nmembs; ++i, ++vdesc) {
+		if (nilfs_vdesc_snapshot(vdesc)) {
+			ret = nilfs_dat_clean_snapshot_flag(nilfs->ns_dat,
+					vdesc->vd_vblocknr);
+			if (ret) {
+				nilfs_transaction_abort(inode->i_sb);
+				goto out_free;
+			}
+		}
+	}
+
+	nilfs_transaction_commit(inode->i_sb);
+
+out_free:
+	vfree(kbuf);
+out:
+	mnt_drop_write_file(filp);
+	return ret;
+}
+
+/**
  * nilfs_ioctl_sync - make a checkpoint
  * @inode: inode object
  * @filp: file object
@@ -1332,6 +1430,8 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
 	case NILFS_IOCTL_CLEAN_SEGMENTS:
 		return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
+	case NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS:
+		return nilfs_ioctl_clean_snapshot_flags(inode, filp, cmd, argp);
 	case NILFS_IOCTL_SYNC:
 		return nilfs_ioctl_sync(inode, filp, cmd, argp);
 	case NILFS_IOCTL_RESIZE:

fs/nilfs2/ioctl.c long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · line 1471

Quoted 4 lines
fs/nilfs2/ioctl.c +1 -0
@@ -1368,6 +1468,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	case NILFS_IOCTL_GET_VINFO:
 	case NILFS_IOCTL_GET_BDESCS:
 	case NILFS_IOCTL_CLEAN_SEGMENTS:
+	case NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS:

Sounds for me that we clean all snapshot's flags.

include/linux/nilfs2_fs.h struct nilfs_vinfo { · line 866

Quoted 13 lines
fs/nilfs2/ioctl.c +0 -0
 	case NILFS_IOCTL_SYNC:
 	case NILFS_IOCTL_RESIZE:
 	case NILFS_IOCTL_SET_ALLOC_RANGE:
include/linux/nilfs2_fs.h +1 -1
index ba9ebe02..30ddc86 100644
@@ -863,7 +863,7 @@ struct nilfs_vinfo {
  * @vd_blocknr: disk block number
  * @vd_offset: logical block offset inside a file
  * @vd_flags: flags (data or node block)
- * @vd_pad: padding
+ * @vd_flags2: additional flags

Ditto. Weird name.

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 876

Quoted 9 lines
include/linux/nilfs2_fs.h +1 -1
  */
 struct nilfs_vdesc {
 	__u64 vd_ino;
@@ -873,9 +873,55 @@ struct nilfs_vdesc {
 	__u64 vd_blocknr;
 	__u64 vd_offset;
 	__u32 vd_flags;
-	__u32 vd_pad;
+	/* vd_flags2 needed because of backwards compatibility */

Completely, misunderstand comment. Usually, it keeps old fields for backward compatibility. But this flag is new.

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 880

Quoted 4 lines
include/linux/nilfs2_fs.h +2 -0
+	__u32 vd_flags2;
 };
 
+/* vdesc flags */

To be honest, I misunderstand why such number of flags and why namely such flags? Comments are really necessary.

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 884

Quoted 4 lines
include/linux/nilfs2_fs.h +4 -0
+enum {
+	NILFS_VDESC_DATA,
+	NILFS_VDESC_NODE,
+	/* ... */

What does it mean?

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 889

Quoted 5 lines
include/linux/nilfs2_fs.h +5 -0
+};
+enum {
+	NILFS_VDESC_SNAPSHOT,
+	__NR_NILFS_VDESC_FIELDS,
+	/* ... */

What does it mean?

Thanks,
Vyacheslav Dubeyko.

Quoted 39 lines
include/linux/nilfs2_fs.h +35 -0
+};
+
+#define NILFS_VDESC_FNS(flag, name)					\
+static inline void							\
+nilfs_vdesc_set_##name(struct nilfs_vdesc *vdesc)			\
+{									\
+	vdesc->vd_flags = NILFS_VDESC_##flag;				\
+}									\
+static inline int							\
+nilfs_vdesc_##name(const struct nilfs_vdesc *vdesc)			\
+{									\
+	return vdesc->vd_flags == NILFS_VDESC_##flag;			\
+}
+
+#define NILFS_VDESC_FNS2(flag, name)					\
+static inline void							\
+nilfs_vdesc_set_##name(struct nilfs_vdesc *vdesc)			\
+{									\
+	vdesc->vd_flags2 |= (1UL << NILFS_VDESC_##flag);		\
+}									\
+static inline void							\
+nilfs_vdesc_clear_##name(struct nilfs_vdesc *vdesc)			\
+{									\
+	vdesc->vd_flags2 &= ~(1UL << NILFS_VDESC_##flag);		\
+}									\
+static inline int							\
+nilfs_vdesc_##name(const struct nilfs_vdesc *vdesc)			\
+{									\
+	return !!(vdesc->vd_flags2 & (1UL << NILFS_VDESC_##flag));	\
+}
+
+NILFS_VDESC_FNS(DATA, data)
+NILFS_VDESC_FNS(NODE, node)
+NILFS_VDESC_FNS2(SNAPSHOT, snapshot)
+
 /**
  * struct nilfs_bdesc - descriptor of disk block number
  * @bd_ino: inode number

include/linux/nilfs2_fs.h struct nilfs_bdesc { · line 974

Quoted 7 lines
include/linux/nilfs2_fs.h +2 -0
@@ -922,5 +968,7 @@ struct nilfs_bdesc {
 	_IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
 #define NILFS_IOCTL_SET_SUINFO  \
 	_IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
+#define NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS  \
+	_IOW(NILFS_IOCTL_IDENT, 0x8F, struct nilfs_argv)
 
 #endif	/* _LINUX_NILFS_FS_H */

--
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

#29 lore raw

Re: [PATCH 4/6] nilfs2: add ioctl() to clean snapshot flags from dat entries

Quoted 7 lines · Vyacheslav Dubeyko
Quoted 5 lines · Andreas Rohner

This patch introduces new flags for nilfs_vdesc to indicate the reason a block is alive. So if the block would be reclaimable, but must be treated as if it were alive, because it is part of a snapshot, then the snapshot flag is set.

Quoted 5 lines

I suppose that I don't quite follow your idea. As far as I can judge, every block in DAT file has: (1) de_start: start checkpoint number; (2)
de_end: end checkpoint number. So, while one of checkpoint number is snapshot number then we know that this block lives in snapshot. Am I correct? Why do we need in special flags?

Yes, but a snapshot can also be in between de_start and de_end. So to check it you would have to get a list of all snapshots and look if one of them is within the range of de_start to de_end. The userspace tools already do this. The flags in nilfs_vdesc are there so that I don't have to check it again in the kernel.

Quoted 41 lines
Quoted 41 lines

Additionally a new ioctl() is added, which enables the userspace GC to perform a cleanup operation after setting the number of blocks with NILFS_IOCTL_SET_SUINFO. It sets DAT entries with de_ss values of NILFS_CNO_MAX to 0. NILFS_CNO_MAX indicates, that the corresponding block belongs to some snapshot, but was already decremented by a previous deletion operation. If the segment usage info is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated, then these blocks would never be decremented and there are scenarios where the corresponding segments would starve (never be cleaned). To prevent that they must be reset to 0.

---
 fs/nilfs2/dat.c           |  63 ++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           |   1 +
 fs/nilfs2/ioctl.c         | 103 +++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/nilfs2_fs.h |  52 ++++++++++++++++++++++-
 4 files changed, 216 insertions(+), 3 deletions(-)
fs/nilfs2/dat.c +14 -0
index 89a4a5f..7adb15d 100644
@@ -382,6 +382,69 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr)
 }
 
 /**
+ * nilfs_dat_clean_snapshot_flag - check flags used by snapshots
+ * @dat: DAT file inode
+ * @vblocknr: virtual block number
+ *
+ * Description: nilfs_dat_clean_snapshot_flag() changes the flags from
+ * NILFS_CNO_MAX to 0 if necessary, so that segment usage is accurately
+ * counted. NILFS_CNO_MAX indicates, that the corresponding block belongs
+ * to some snapshot, but was already decremented. If the segment usage info
+ * is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated,
+ * then these blocks would never be decremented and there are scenarios where
+ * the corresponding segments would starve (never be cleaned).
+ *
+ * Return Value: On success, 0 is returned. On error, one of the following
+ * negative error codes is returned.
Quoted 8 lines

fs/nilfs2/dat.c int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) · line 404

Quoted 6 lines
fs/nilfs2/dat.c +6 -0
+ *
+ * %-EIO - I/O error.
+ *
+ * %-ENOMEM - Insufficient amount of memory available.
+ */
+int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr)

Sounds likewise we clear flag. It can be confusing name.

Yes it is hard to get a good name for that function. It has nothing to do with the nilfs_vdesc flags.

Quoted 30 lines
Quoted 30 lines
fs/nilfs2/dat.c +30 -0
+{
+	struct buffer_head *entry_bh;
+	struct nilfs_dat_entry *entry;
+	void *kaddr;
+	int ret;
+
+	ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The given disk block number (blocknr) is not yet written to
+	 * the device at this point.
+	 *
+	 * To prevent nilfs_dat_translate() from returning the
+	 * uncommitted block number, this makes a copy of the entry
+	 * buffer and redirects nilfs_dat_translate() to the copy.
+	 */
+	if (!buffer_nilfs_redirected(entry_bh)) {
+		ret = nilfs_mdt_freeze_buffer(dat, entry_bh);
+		if (ret) {
+			brelse(entry_bh);
+			return ret;
+		}
+	}
+
+	kaddr = kmap_atomic(entry_bh->b_page);
+	entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr);
+	if (entry->de_ss == cpu_to_le64(NILFS_CNO_MAX)) {
+		entry->de_ss = cpu_to_le64(0);
Quoted 8 lines

fs/nilfs2/dat.c int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) · line 440

Quoted 6 lines
fs/nilfs2/dat.c +6 -0
+		kunmap_atomic(kaddr);
+		mark_buffer_dirty(entry_bh);
+		nilfs_mdt_mark_dirty(dat);
+	} else {
+		kunmap_atomic(kaddr);
+	}

Brackets are unnecessary here.

Yes.

Quoted 38 lines
Quoted 38 lines
fs/nilfs2/dat.c +7 -0
+
+	brelse(entry_bh);
+
+	return 0;
+}
+
+/**
  * nilfs_dat_translate - translate a virtual block number to a block number
  * @dat: DAT file inode
  * @vblocknr: virtual block number
fs/nilfs2/dat.h +1 -0
index 92a187e..a528024 100644
@@ -51,6 +51,7 @@ void nilfs_dat_abort_update(struct inode *, struct nilfs_palloc_req *,
 int nilfs_dat_mark_dirty(struct inode *, __u64);
 int nilfs_dat_freev(struct inode *, __u64 *, size_t);
 int nilfs_dat_move(struct inode *, __u64, sector_t);
+int nilfs_dat_clean_snapshot_flag(struct inode *, __u64);
 ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t);
 
 int nilfs_dat_read(struct super_block *sb, size_t entry_size,
fs/nilfs2/ioctl.c +1 -1
index 422fb54..0b62bf4 100644
@@ -578,7 +578,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
 	struct buffer_head *bh;
 	int ret;
 
-	if (vdesc->vd_flags == 0)
+	if (nilfs_vdesc_data(vdesc))
 		ret = nilfs_gccache_submit_read_data(
 			inode, vdesc->vd_offset, vdesc->vd_blocknr,
 			vdesc->vd_vblocknr, &bh);
@@ -662,6 +662,14 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb,
 		}
 
Quoted 8 lines

fs/nilfs2/ioctl.c static int nilfs_ioctl_move_blocks(struct super_block *sb, · line 669

Quoted 6 lines
fs/nilfs2/ioctl.c +5 -0
 		do {
+			/*
+			 * old user space tools to not initialize vd_flags2
+			 * check if it contains invalid flags
+			 */
+			if (vdesc->vd_flags2 &

"vd_flags2" is really bad naming. Completely obscure.

I would like to use the already existing field vd_flags, but that is impossible because of backwards compatibility.

Quoted 142 lines

fs/nilfs2/ioctl.c static int nilfs_ioctl_move_blocks(struct super_block *sb, · line 670

Quoted 1 line
fs/nilfs2/ioctl.c +1 -0
+					(~0UL << __NR_NILFS_VDESC_FIELDS))

Looks weird.

fs/nilfs2/ioctl.c out: · line 995

Quoted 10 lines
fs/nilfs2/ioctl.c +3 -0
+				vdesc->vd_flags2 = 0;
+
 			ret = nilfs_ioctl_move_inode_block(inode, vdesc,
 							   &buffers);
 			if (unlikely(ret < 0)) {
@@ -984,6 +992,96 @@ out:
 }
 
 /**
+ * nilfs_ioctl_clean_snapshot_flags - clean dat entries with invalid de_ss

Ditto. Sounds likewise clearing of flag.

Quoted 102 lines
fs/nilfs2/ioctl.c +91 -0
+ * @inode: inode object
+ * @filp: file object
+ * @cmd: ioctl's request code
+ * @argp: pointer on argument from userspace
+ *
+ * Description: nilfs_ioctl_clean_snapshot_flags() sets DAT entries with de_ss
+ * values of NILFS_CNO_MAX to 0. NILFS_CNO_MAX indicates, that the
+ * corresponding block belongs to some snapshot, but was already decremented.
+ * If the segment usage info is changed with NILFS_IOCTL_SET_SUINFO and the
+ * number of blocks is updated, then these blocks would never be decremented
+ * and there are scenarios where the corresponding segments would starve (never
+ * be cleaned).
+ *
+ * Return Value: On success, 0 is returned or error code, otherwise.
+ */
+static int nilfs_ioctl_clean_snapshot_flags(struct inode *inode,
+					    struct file *filp,
+					    unsigned int cmd,
+					    void __user *argp)
+{
+	struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
+	struct nilfs_transaction_info ti;
+	struct nilfs_argv argv;
+	struct nilfs_vdesc *vdesc;
+	size_t len, i;
+	void __user *base;
+	void *kbuf;
+	int ret;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ret = mnt_want_write_file(filp);
+	if (ret)
+		return ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&argv, argp, sizeof(struct nilfs_argv)))
+		goto out;
+
+	ret = -EINVAL;
+	if (argv.v_size != sizeof(struct nilfs_vdesc))
+		goto out;
+	if (argv.v_nmembs > UINT_MAX / sizeof(struct nilfs_vdesc))
+		goto out;
+
+	len = argv.v_size * argv.v_nmembs;
+	if (!len) {
+		ret = 0;
+		goto out;
+	}
+
+	base = (void __user *)(unsigned long)argv.v_base;
+	kbuf = vmalloc(len);
+	if (!kbuf) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (copy_from_user(kbuf, base, len)) {
+		ret = -EFAULT;
+		goto out_free;
+	}
+
+	ret = nilfs_transaction_begin(inode->i_sb, &ti, 0);
+	if (unlikely(ret))
+		goto out_free;
+
+	for (i = 0, vdesc = kbuf; i < argv.v_nmembs; ++i, ++vdesc) {
+		if (nilfs_vdesc_snapshot(vdesc)) {
+			ret = nilfs_dat_clean_snapshot_flag(nilfs->ns_dat,
+					vdesc->vd_vblocknr);
+			if (ret) {
+				nilfs_transaction_abort(inode->i_sb);
+				goto out_free;
+			}
+		}
+	}
+
+	nilfs_transaction_commit(inode->i_sb);
+
+out_free:
+	vfree(kbuf);
+out:
+	mnt_drop_write_file(filp);
+	return ret;
+}
+
+/**
  * nilfs_ioctl_sync - make a checkpoint
  * @inode: inode object
  * @filp: file object
@@ -1332,6 +1430,8 @@ long nilfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 		return nilfs_ioctl_get_bdescs(inode, filp, cmd, argp);
 	case NILFS_IOCTL_CLEAN_SEGMENTS:
 		return nilfs_ioctl_clean_segments(inode, filp, cmd, argp);
+	case NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS:
+		return nilfs_ioctl_clean_snapshot_flags(inode, filp, cmd, argp);
 	case NILFS_IOCTL_SYNC:
 		return nilfs_ioctl_sync(inode, filp, cmd, argp);
 	case NILFS_IOCTL_RESIZE:

fs/nilfs2/ioctl.c long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · line 1471

Quoted 4 lines
fs/nilfs2/ioctl.c +1 -0
@@ -1368,6 +1468,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 	case NILFS_IOCTL_GET_VINFO:
 	case NILFS_IOCTL_GET_BDESCS:
 	case NILFS_IOCTL_CLEAN_SEGMENTS:
+	case NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS:

Sounds for me that we clean all snapshot's flags.

include/linux/nilfs2_fs.h struct nilfs_vinfo { · line 866

Quoted 13 lines
fs/nilfs2/ioctl.c +0 -0
 	case NILFS_IOCTL_SYNC:
 	case NILFS_IOCTL_RESIZE:
 	case NILFS_IOCTL_SET_ALLOC_RANGE:
include/linux/nilfs2_fs.h +1 -1
index ba9ebe02..30ddc86 100644
@@ -863,7 +863,7 @@ struct nilfs_vinfo {
  * @vd_blocknr: disk block number
  * @vd_offset: logical block offset inside a file
  * @vd_flags: flags (data or node block)
- * @vd_pad: padding
+ * @vd_flags2: additional flags

Ditto. Weird name.

Quoted 12 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 876

Quoted 9 lines
include/linux/nilfs2_fs.h +1 -1
  */
 struct nilfs_vdesc {
 	__u64 vd_ino;
@@ -873,9 +873,55 @@ struct nilfs_vdesc {
 	__u64 vd_blocknr;
 	__u64 vd_offset;
 	__u32 vd_flags;
-	__u32 vd_pad;
+	/* vd_flags2 needed because of backwards compatibility */

Completely, misunderstand comment. Usually, it keeps old fields for backward compatibility. But this flag is new.

I will rewrite the comment. I need vd_flags2 because I can't use vd_flags because of backwards compatibility.

Quoted 8 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 880

Quoted 4 lines
include/linux/nilfs2_fs.h +2 -0
+	__u32 vd_flags2;
 };
 
+/* vdesc flags */

To be honest, I misunderstand why such number of flags and why namely such flags? Comments are really necessary.

Quoted 6 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 884

Quoted 4 lines
include/linux/nilfs2_fs.h +4 -0
+enum {
+	NILFS_VDESC_DATA,
+	NILFS_VDESC_NODE,
+	/* ... */

What does it mean?

NILFS_VDESC_DATA = 0 and NILFS_VDESC_NODE = 1. This represents the type of block. These two already existed, in the previous version, but they were not explicit. See "[Patch 4/4] nilfs-utils: add extra flags to nilfs_vdesc and update sui_nblocks":

@@ -148,17 +149,19 @@ static int nilfs_acc_blocks_file(struct nilfs_file *file,
- vdesc->vd_flags = 0; /* data */
+ nilfs_vdesc_set_data(vdesc);
} else {
vdesc->vd_vblocknr =
le64_to_cpu(*(__le64 *)blk.b_binfo);
- vdesc->vd_flags = 1; /* node */
+ nilfs_vdesc_set_node(vdesc);
}

Quoted 7 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 889

Quoted 5 lines
include/linux/nilfs2_fs.h +5 -0
+};
+enum {
+	NILFS_VDESC_SNAPSHOT,
+	__NR_NILFS_VDESC_FIELDS,
+	/* ... */

What does it mean?

Those flags are set by the userspace tools in nilfs_vdesc_is_live(). They indicate the reason why a block is alive. NILFS_VDESC_SNAPSHOT means, that the block is alive because it belongs to a snapshot.

nilfs_vdesc is a data structure for the communication between kernelspace and userspace. You have to look at it in that context.

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

A message that is not in the archive (sent off-list or not yet received): [email protected]

#31 lore raw

Re: [PATCH 4/6] nilfs2: add ioctl() to clean snapshot flags from dat entries

Quoted 14 lines · Andreas Rohner
Quoted 13 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 876

Quoted 10 lines

*/
struct nilfs_vdesc {

include/linux/nilfs2_fs.h +1 -1
 	__u64 vd_ino;
@@ -873,9 +873,55 @@ struct nilfs_vdesc {
 	__u64 vd_blocknr;
 	__u64 vd_offset;
 	__u32 vd_flags;
-	__u32 vd_pad;
+	/* vd_flags2 needed because of backwards compatibility */

Completely, misunderstand comment. Usually, it keeps old fields for backward compatibility. But this flag is new.

Quoted 4 lines

I will rewrite the comment. I need vd_flags2 because I can't use vd_flags because of backwards compatibility.

Quoted 1 line

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 877

Quoted 1 line
include/linux/nilfs2_fs.h +1 -0
+	__u32 vd_flags2;

What about vd_blk_state instead of vd_flags2?

Quoted 34 lines
Quoted 7 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 880

Quoted 3 lines
include/linux/nilfs2_fs.h +1 -0
 };
 
+/* vdesc flags */

To be honest, I misunderstand why such number of flags and why namely such flags? Comments are really necessary.

Quoted 6 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 884

Quoted 4 lines
include/linux/nilfs2_fs.h +4 -0
+enum {
+	NILFS_VDESC_DATA,
+	NILFS_VDESC_NODE,
+	/* ... */

What does it mean?

NILFS_VDESC_DATA = 0 and NILFS_VDESC_NODE = 1. This represents the type of block. These two already existed, in the previous version, but they were not explicit. See "[Patch 4/4] nilfs-utils: add extra flags to nilfs_vdesc and update sui_nblocks":

(quoted diff) +2 -2
@@ -148,17 +149,19 @@ static int nilfs_acc_blocks_file(struct nilfs_file
 *file,
-				vdesc->vd_flags = 0;	/* data */
+				nilfs_vdesc_set_data(vdesc);
 			} else {
 				vdesc->vd_vblocknr =
 					le64_to_cpu(*(__le64 *)blk.b_binfo);
-				vdesc->vd_flags = 1;	/* node */
+				nilfs_vdesc_set_node(vdesc);
 			}
 
 >> +};
 >> +enum {
 >> +	NILFS_VDESC_SNAPSHOT,
 >> +	__NR_NILFS_VDESC_FIELDS,
Quoted 3 lines
Quoted 3 lines

Review struct nilfs_vdesc { · line 885

Quoted 1 line
(quoted diff) +1 -0
+	/* ... */

What does it mean?

I asked here about strange comment. What does it mean?

Moreover, I slightly confused by NILFS_VDESC_SNAPSHOT. Is it bit-based flag? I mean NILFS_VDESC_SNAPSHOT = (1 << 0). Or am I incorrect?

Thanks,
Vyacheslav Dubeyko.

--
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

#32 lore raw

Re: [PATCH 4/6] nilfs2: add ioctl() to clean snapshot flags from dat entries

Quoted 16 lines · Vyacheslav Dubeyko
Quoted 14 lines · Andreas Rohner
Quoted 13 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 876

Quoted 10 lines

*/
struct nilfs_vdesc {

include/linux/nilfs2_fs.h +1 -1
 	__u64 vd_ino;
@@ -873,9 +873,55 @@ struct nilfs_vdesc {
 	__u64 vd_blocknr;
 	__u64 vd_offset;
 	__u32 vd_flags;
-	__u32 vd_pad;
+	/* vd_flags2 needed because of backwards compatibility */

Completely, misunderstand comment. Usually, it keeps old fields for backward compatibility. But this flag is new.

Quoted 6 lines
Quoted 4 lines

I will rewrite the comment. I need vd_flags2 because I can't use vd_flags because of backwards compatibility.

Quoted 1 line

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 877

Quoted 1 line
include/linux/nilfs2_fs.h +1 -0
+	__u32 vd_flags2;

What about vd_blk_state instead of vd_flags2?

Yes sounds good to me.

Quoted 38 lines
Quoted 34 lines
Quoted 7 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 880

Quoted 3 lines
include/linux/nilfs2_fs.h +1 -0
 };
 
+/* vdesc flags */

To be honest, I misunderstand why such number of flags and why namely such flags? Comments are really necessary.

Quoted 6 lines

include/linux/nilfs2_fs.h struct nilfs_vdesc { · line 884

Quoted 4 lines
include/linux/nilfs2_fs.h +4 -0
+enum {
+	NILFS_VDESC_DATA,
+	NILFS_VDESC_NODE,
+	/* ... */

What does it mean?

NILFS_VDESC_DATA = 0 and NILFS_VDESC_NODE = 1. This represents the type of block. These two already existed, in the previous version, but they were not explicit. See "[Patch 4/4] nilfs-utils: add extra flags to nilfs_vdesc and update sui_nblocks":

(quoted diff) +2 -2
@@ -148,17 +149,19 @@ static int nilfs_acc_blocks_file(struct nilfs_file
 *file,
-				vdesc->vd_flags = 0;	/* data */
+				nilfs_vdesc_set_data(vdesc);
 			} else {
 				vdesc->vd_vblocknr =
 					le64_to_cpu(*(__le64 *)blk.b_binfo);
-				vdesc->vd_flags = 1;	/* node */
+				nilfs_vdesc_set_node(vdesc);
 			}
 
 >> +};
 >> +enum {
 >> +	NILFS_VDESC_SNAPSHOT,
 >> +	__NR_NILFS_VDESC_FIELDS,
Quoted 3 lines
Quoted 3 lines

Review struct nilfs_vdesc { · line 885

Quoted 1 line
(quoted diff) +1 -0
+	/* ... */

What does it mean?

Quoted 1 line

I asked here about strange comment. What does it mean?

Sorry for the misunderstanding. I copied the comment from other flags like:

enum {
	NILFS_SEGMENT_USAGE_ACTIVE,
	NILFS_SEGMENT_USAGE_DIRTY,
	NILFS_SEGMENT_USAGE_ERROR,

	/* ... */
};

I guess it means "additional flags come here".

But you are right it is confusing it should be like that:

enum {
	NILFS_VDESC_SNAPSHOT,
	NILFS_VDESC_PROTECTION_PERIOD,

	/* ... */

	__NR_NILFS_VDESC_FIELDS,
};
Quoted 2 lines

Moreover, I slightly confused by NILFS_VDESC_SNAPSHOT. Is it bit-based flag? I mean NILFS_VDESC_SNAPSHOT = (1 << 0). Or am I incorrect?

Yes NILFS_VDESC_SNAPSHOT and NILFS_VDESC_PROTECTION_PERIOD are bit-based. NILFS_VDESC_DATA and NILFS_VDESC_NODE are not bit-based because of backwards compatibility.

Please also note, that [PATCH 5/6] adds another flag, namely NILFS_VDESC_PROTECTION_PERIOD.

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

#33 lore raw

PATCH 5/6 nilfs2: add counting of live blocks for blocks that are overwritten

In reply to a message not in the archive

After a Block is written to disk, the buffer_head is never mapped to that location on disk. By simply using map_bh() after writing the block the origin of overwritten blocks can be determined and the corresponding segment can be calculated with nilfs_get_segnum_of_block(). Since the block is now at a new location, the old one is reclaimable. Therefore the number of live blocks in the segment usage information of the segment of the previous location of the block needs to be decremented. This approach also works for the DAT file and other metadata files.

nilfs_node Blocks have to be treated differently. Also GC blocks have to be treated separately, because they contain the virtual block number in the b_blocknr field and their old location is about to be cleaned anyway. So it is not necessary to decrement the live block counters for GC blocks.

This patch does not count deleted blocks, when a whole file is deleted.

---
 fs/nilfs2/dat.c           | 58 +++++++++++++++++++++++++++++++++++++++
 fs/nilfs2/dat.h           |  1 +
 fs/nilfs2/inode.c         |  2 ++
 fs/nilfs2/ioctl.c         |  6 +++++
 fs/nilfs2/page.h          |  6 ++++-
 fs/nilfs2/segbuf.c        | 25 +++++++++++++++++
 fs/nilfs2/segbuf.h        |  4 +++
 fs/nilfs2/segment.c       | 69 +++++++++++++++++++++++++++++++++++++++++++----
 include/linux/nilfs2_fs.h |  2 ++
 9 files changed, 167 insertions(+), 6 deletions(-)
fs/nilfs2/dat.c +58 -0
index 7adb15d..e7b19c40 100644
@@ -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
+ * @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.
+ *
+ * %-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) {
+		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
fs/nilfs2/dat.h +1 -0
index a528024..51d44c0 100644
@@ -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 *);
fs/nilfs2/inode.c +2 -0
index b9c5726..c32b896 100644
@@ -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);
fs/nilfs2/ioctl.c +6 -0
index 0b62bf4..3603394 100644
@@ -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;
 }
fs/nilfs2/page.h +5 -1
index ef30c5c..8c34a31 100644
@@ -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 *);
 
fs/nilfs2/segbuf.c +25 -0
index dc3a9efd..c72fc37 100644
@@ -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)
+		return -1;
+
+	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;
 	}
fs/nilfs2/segbuf.h +4 -0
index b04f08c..482bbad 100644
@@ -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);
fs/nilfs2/segment.c +64 -5

125 lines not on this page · raw message

include/linux/nilfs2_fs.h +2 -0
index 30ddc86..e05793a 100644
@@ -885,6 +885,7 @@ enum {
 };
 enum {
 	NILFS_VDESC_SNAPSHOT,
+	NILFS_VDESC_PROTECTION_PERIOD,
 	__NR_NILFS_VDESC_FIELDS,
 	/* ... */
 };
@@ -921,6 +922,7 @@ nilfs_vdesc_##name(const struct nilfs_vdesc *vdesc)			\
 NILFS_VDESC_FNS(DATA, data)
 NILFS_VDESC_FNS(NODE, node)
 NILFS_VDESC_FNS2(SNAPSHOT, snapshot)
+NILFS_VDESC_FNS2(PROTECTION_PERIOD, protection_period)
 
 /**
  * struct nilfs_bdesc - descriptor of disk block number
Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): 25dd8a8bb6943ffa3e0663848363135585a48109.1394966729.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#35 lore raw

Re: [PATCH 5/6] nilfs2: add counting of live blocks for blocks that are overwritten

fs/nilfs2/dat.c int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr) · line 448

Quoted 9 lines · Andreas Rohner
fs/nilfs2/dat.c +1 -0
index 7adb15d..e7b19c40 100644
@@ -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?

fs/nilfs2/dat.c int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr) · line 457

Quoted 9 lines
fs/nilfs2/dat.c +9 -0
+ * @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.

Quoted 22 lines
fs/nilfs2/dat.c +22 -0
+ *
+ * %-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) {

fs/nilfs2/dat.c int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr) · line 489

Quoted 10 lines
fs/nilfs2/dat.c +10 -0
+			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?

Quoted 108 lines
fs/nilfs2/dat.c +16 -0
+		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
fs/nilfs2/dat.h +1 -0
index a528024..51d44c0 100644
@@ -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 *);
fs/nilfs2/inode.c +2 -0
index b9c5726..c32b896 100644
@@ -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);
fs/nilfs2/ioctl.c +6 -0
index 0b62bf4..3603394 100644
@@ -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;
 }
fs/nilfs2/page.h +5 -1
index ef30c5c..8c34a31 100644
@@ -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 *);
 
fs/nilfs2/segbuf.c +3 -0
index dc3a9efd..c72fc37 100644
@@ -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;
 }

fs/nilfs2/segbuf.c void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum, · line 96

Quoted 10 lines
fs/nilfs2/segbuf.c +9 -0
 
+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?

fs/nilfs2/segbuf.c void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum, · line 97

Quoted 1 line
fs/nilfs2/segbuf.c +1 -0
+		return -1;

It is really bad idea. Finally, caller will have -EPERM. Do you mean this here?

Quoted 114 lines
fs/nilfs2/segbuf.c +12 -0
+
+	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;
 	}
fs/nilfs2/segbuf.h +4 -0
index b04f08c..482bbad 100644
@@ -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);
fs/nilfs2/segment.c +16 -5
index a1a1916..5d98a1c 100644
@@ -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;

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1524

Quoted 6 lines
fs/nilfs2/segment.c +3 -0
@@ -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.

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1528

Quoted 4 lines
fs/nilfs2/segment.c +4 -0
+			/* 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).

Quoted 14 lines
fs/nilfs2/segment.c +7 -0
+
+			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 &&

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1552

Quoted 10 lines
fs/nilfs2/segment.c +10 -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.

Quoted 8 lines
fs/nilfs2/segment.c +8 -0
+				}
+				prev_segnum = segnum;
+				blkcount = 0;
+				maxdectime = dectime;
+			}
+
+
+			if (segnum == segbuf->sb_segnum)

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1570

Quoted 10 lines
fs/nilfs2/segment.c +10 -0
+				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. :)

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1599

Quoted 13 lines
fs/nilfs2/segment.c +6 -0
+		}
+
 		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.

Thanks,
Vyacheslav Dubeyko.

Quoted 16 lines
fs/nilfs2/segment.c +0 -0
  out:
 	return 0;
 
include/linux/nilfs2_fs.h +1 -0
index 30ddc86..e05793a 100644
@@ -885,6 +885,7 @@ enum {
 };
 enum {
 	NILFS_VDESC_SNAPSHOT,
+	NILFS_VDESC_PROTECTION_PERIOD,
 	__NR_NILFS_VDESC_FIELDS,
 	/* ... */
 };

include/linux/nilfs2_fs.h nilfs_vdesc_##name(const struct nilfs_vdesc *vdesc) \ · line 928

Quoted 7 lines
include/linux/nilfs2_fs.h +1 -0
@@ -921,6 +922,7 @@ nilfs_vdesc_##name(const struct nilfs_vdesc *vdesc)			\
 NILFS_VDESC_FNS(DATA, data)
 NILFS_VDESC_FNS(NODE, node)
 NILFS_VDESC_FNS2(SNAPSHOT, snapshot)
+NILFS_VDESC_FNS2(PROTECTION_PERIOD, protection_period)
 
 /**
  * struct nilfs_bdesc - descriptor of disk block number

--
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

#36 lore raw

Re: [PATCH 5/6] nilfs2: add counting of live blocks for blocks that are overwritten

Quoted 9 lines · Vyacheslav Dubeyko
Quoted 7 lines · Andreas Rohner
fs/nilfs2/dat.c +0 -0
index 7adb15d..e7b19c40 100644
@@ -445,6 +445,64 @@ int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr)
 }
 
Quoted 4 lines

fs/nilfs2/dat.c int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr) · line 448

Quoted 2 lines
fs/nilfs2/dat.c +1 -0
 /**
+ * nilfs_dat_is_live - checks if the virtual block number is alive

What about nilfs_dat_block_is_alive?

Yes sounds good.

Quoted 10 lines

fs/nilfs2/dat.c int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr) · line 457

Quoted 9 lines
fs/nilfs2/dat.c +9 -0
+ * @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.
Quoted 6 lines

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.

Quoted 26 lines
Quoted 26 lines
fs/nilfs2/dat.c +26 -0
+ *
+ * %-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;
+		}
Quoted 8 lines

fs/nilfs2/dat.c int nilfs_dat_clean_snapshot_flag(struct inode *dat, __u64 vblocknr) · line 489

Quoted 6 lines
fs/nilfs2/dat.c +6 -0
+	}
+
+	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 ;)

Quoted 109 lines
Quoted 109 lines
fs/nilfs2/dat.c +16 -0
+		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
fs/nilfs2/dat.h +1 -0
index a528024..51d44c0 100644
@@ -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 *);
fs/nilfs2/inode.c +2 -0
index b9c5726..c32b896 100644
@@ -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);
fs/nilfs2/ioctl.c +6 -0
index 0b62bf4..3603394 100644
@@ -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;
 }
fs/nilfs2/page.h +5 -1
index ef30c5c..8c34a31 100644
@@ -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 *);
 
fs/nilfs2/segbuf.c +3 -0
index dc3a9efd..c72fc37 100644
@@ -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;
 }
 
Quoted 12 lines

fs/nilfs2/segbuf.c void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum, · line 96

Quoted 9 lines
fs/nilfs2/segbuf.c +9 -0
+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.

Quoted 5 lines

fs/nilfs2/segbuf.c void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum, · line 97

Quoted 2 lines
fs/nilfs2/segbuf.c +1 -0
+		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;
Quoted 115 lines
Quoted 115 lines
fs/nilfs2/segbuf.c +12 -0
+
+	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;
 	}
fs/nilfs2/segbuf.h +4 -0
index b04f08c..482bbad 100644
@@ -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);
fs/nilfs2/segment.c +16 -5
index a1a1916..5d98a1c 100644
@@ -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,
 
Quoted 7 lines

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1524

Quoted 5 lines
fs/nilfs2/segment.c +3 -0
 			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...

Quoted 7 lines

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1528

Quoted 4 lines
fs/nilfs2/segment.c +4 -0
+			/* no update of lastdec necessary */
+			if (ino == NILFS_DAT_INO || ino == NILFS_SUFILE_INO ||
+					ino == NILFS_CPFILE_INO)
+				dectime = 0;

What about such?

Quoted 7 lines

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.

Quoted 41 lines
Quoted 14 lines
fs/nilfs2/segment.c +7 -0
+
+			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 &&

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1552

Quoted 10 lines
fs/nilfs2/segment.c +10 -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.

Quoted 13 lines
fs/nilfs2/segment.c +13 -0
+				}
+				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 */
Quoted 8 lines

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1570

Quoted 5 lines
fs/nilfs2/segment.c +5 -0
+			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.

Quoted 8 lines
Quoted 8 lines
fs/nilfs2/segment.c +2 -0
+		}
+
 		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--;
Quoted 8 lines

fs/nilfs2/segment.c nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, · line 1599

Quoted 5 lines
fs/nilfs2/segment.c +4 -0
 	}
+
+	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

#37 lore raw

PATCH 6/6 nilfs2: add counting of live blocks for deleted files

In reply to a message not in the archive

If a file is deleted, then the entries of its blocks in the DAT-File need to be updated. So everytime a file is deleted nilfs_dat_commit_end() is called for every block to set de_end to the current checkpoint number. So it is the perfect hook to insert logic that counts live blocks. If the file is deleted, then the blocks are reclaimable and the number of live blocks for the corresponding segments must be decremented. This patch adds code to nilfs_dat_commit_end() that decrements the number of live blocks under certain conditions.

One condition is, that the block must not belong to the SUFILE, because that would lead to a deadlock. When nilfs_dat_commit_end() is called the bmaps b_sem is already held, but nilfs_sufile_add_segment_usage() has to lock that same lock for the SUFILE, to decrement the number of live blocks. Secondly the blocks must only be counted if nilfs_dat_commit_end() is called from a file deletion operation, because overwritten blocks are already counted somewhere else.

With the above changes the code does not pass the lock dependency checks, because all the locks have the same class and the order in which the locks are taken is different. Usually it is:

1. down_write(&NILFS_MDT(sufile)->mi_sem);
2. down_write(&bmap->b_sem);

Now it can also be reversed, which leads to failed checks:

1. down_write(&bmap->b_sem); /* lock of a file other than SUFILE */
2. down_write(&NILFS_MDT(sufile)->mi_sem);

But this is safe as long as the first lock down_write(&bmap->b_sem) doesn't belong to the SUFILE. So the warnings can be resolved, by adding an extra lock class for the SUFILE and the code is safe, because the SUFILE is excluded from being counted.

---
 fs/nilfs2/bmap.c   |  8 +++++++-
 fs/nilfs2/bmap.h   |  2 +-
 fs/nilfs2/btree.c  |  3 ++-
 fs/nilfs2/dat.c    | 18 ++++++++++++++----
 fs/nilfs2/dat.h    |  4 ++--
 fs/nilfs2/direct.c |  3 ++-
 fs/nilfs2/mdt.c    |  5 ++++-
 7 files changed, 32 insertions(+), 11 deletions(-)
fs/nilfs2/bmap.c +7 -1
index aadbd0b..ecd62ba 100644
@@ -467,6 +467,7 @@ __u64 nilfs_bmap_find_target_in_group(const struct nilfs_bmap *bmap)
 
 static struct lock_class_key nilfs_bmap_dat_lock_key;
 static struct lock_class_key nilfs_bmap_mdt_lock_key;
+static struct lock_class_key nilfs_bmap_sufile_lock_key;
 
 /**
  * nilfs_bmap_read - read a bmap from an inode
@@ -498,12 +499,17 @@ int nilfs_bmap_read(struct nilfs_bmap *bmap, struct nilfs_inode *raw_inode)
 		lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key);
 		break;
 	case NILFS_CPFILE_INO:
-	case NILFS_SUFILE_INO:
 		bmap->b_ptr_type = NILFS_BMAP_PTR_VS;
 		bmap->b_last_allocated_key = 0;
 		bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR;
 		lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
 		break;
+	case NILFS_SUFILE_INO:
+		bmap->b_ptr_type = NILFS_BMAP_PTR_VS;
+		bmap->b_last_allocated_key = 0;
+		bmap->b_last_allocated_ptr = NILFS_BMAP_INVALID_PTR;
+		lockdep_set_class(&bmap->b_sem, &nilfs_bmap_sufile_lock_key);
+		break;
 	case NILFS_IFILE_INO:
 		lockdep_set_class(&bmap->b_sem, &nilfs_bmap_mdt_lock_key);
 		/* Fall through */
fs/nilfs2/bmap.h +1 -1
index b89e680..f09009c 100644
@@ -223,7 +223,7 @@ static inline void nilfs_bmap_commit_end_ptr(struct nilfs_bmap *bmap,
 {
 	if (dat)
 		nilfs_dat_commit_end(dat, &req->bpr_req,
-				     bmap->b_ptr_type == NILFS_BMAP_PTR_VS);
+				     bmap->b_ptr_type == NILFS_BMAP_PTR_VS, 1);
 }
 
 static inline void nilfs_bmap_abort_end_ptr(struct nilfs_bmap *bmap,
fs/nilfs2/btree.c +2 -1
index b2e3ff3..7365cb4 100644
@@ -1851,7 +1851,8 @@ static void nilfs_btree_commit_update_v(struct nilfs_bmap *btree,
 
 	nilfs_dat_commit_update(dat, &path[level].bp_oldreq.bpr_req,
 				&path[level].bp_newreq.bpr_req,
-				btree->b_ptr_type == NILFS_BMAP_PTR_VS);
+				btree->b_ptr_type == NILFS_BMAP_PTR_VS,
+				buffer_nilfs_node(path[level].bp_bh));
 
 	if (buffer_nilfs_node(path[level].bp_bh)) {
 		nilfs_btnode_commit_change_key(
fs/nilfs2/dat.c +14 -4
index e7b19c40..f465cbf 100644
@@ -188,12 +188,13 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
 }
 
 void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,
-			  int dead)
+			  int dead, int count_blocks)
 {
 	struct nilfs_dat_entry *entry;
 	__u64 start, end;
 	sector_t blocknr;
 	void *kaddr;
+	struct the_nilfs *nilfs;
 
 	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
 	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
@@ -210,8 +211,16 @@ void nilfs_dat_commit_end(struct inode *dat, struct nilfs_palloc_req *req,
 
 	if (blocknr == 0)
 		nilfs_dat_commit_free(dat, req);
-	else
+	else {
 		nilfs_dat_commit_entry(dat, req);
+
+		if (!dead && count_blocks) {
+			nilfs =  dat->i_sb->s_fs_info;
+			nilfs_sufile_add_segment_usage(nilfs->ns_sufile,
+				nilfs_get_segnum_of_block(nilfs, blocknr), -1,
+				nilfs->ns_ctime);
+		}
+	}
 }
 
 void nilfs_dat_abort_end(struct inode *dat, struct nilfs_palloc_req *req)
@@ -250,9 +259,10 @@ int nilfs_dat_prepare_update(struct inode *dat,
 
 void nilfs_dat_commit_update(struct inode *dat,
 			     struct nilfs_palloc_req *oldreq,
-			     struct nilfs_palloc_req *newreq, int dead)
+			     struct nilfs_palloc_req *newreq,
+			     int dead, int count_blocks)
 {
-	nilfs_dat_commit_end(dat, oldreq, dead);
+	nilfs_dat_commit_end(dat, oldreq, dead, count_blocks);
 	nilfs_dat_commit_alloc(dat, newreq);
 }
 
fs/nilfs2/dat.h +2 -2
index 51d44c0..3dc8de8 100644
@@ -40,12 +40,12 @@ int nilfs_dat_prepare_start(struct inode *, struct nilfs_palloc_req *);
 void nilfs_dat_commit_start(struct inode *, struct nilfs_palloc_req *,
 			    sector_t);
 int nilfs_dat_prepare_end(struct inode *, struct nilfs_palloc_req *);
-void nilfs_dat_commit_end(struct inode *, struct nilfs_palloc_req *, int);
+void nilfs_dat_commit_end(struct inode *, struct nilfs_palloc_req *, int, int);
 void nilfs_dat_abort_end(struct inode *, struct nilfs_palloc_req *);
 int nilfs_dat_prepare_update(struct inode *, struct nilfs_palloc_req *,
 			     struct nilfs_palloc_req *);
 void nilfs_dat_commit_update(struct inode *, struct nilfs_palloc_req *,
-			     struct nilfs_palloc_req *, int);
+			     struct nilfs_palloc_req *, int, int);
 void nilfs_dat_abort_update(struct inode *, struct nilfs_palloc_req *,
 			    struct nilfs_palloc_req *);
 
fs/nilfs2/direct.c +2 -1
index 82f4865..c432484 100644
@@ -272,7 +272,8 @@ static int nilfs_direct_propagate(struct nilfs_bmap *bmap,
 		if (ret < 0)
 			return ret;
 		nilfs_dat_commit_update(dat, &oldreq, &newreq,
-					bmap->b_ptr_type == NILFS_BMAP_PTR_VS);
+					bmap->b_ptr_type == NILFS_BMAP_PTR_VS,
+					0);
 		set_buffer_nilfs_volatile(bh);
 		nilfs_direct_set_ptr(bmap, key, newreq.pr_entry_nr);
 	} else
fs/nilfs2/mdt.c +4 -1
index c4dcd1d..1aa3cc5 100644
@@ -414,7 +414,7 @@ static const struct address_space_operations def_mdt_aops = {
 
 static const struct inode_operations def_mdt_iops;
 static const struct file_operations def_mdt_fops;
-
+static struct lock_class_key nilfs_mdt_mi_sufile_lock_key;
 
 int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz)
 {
@@ -427,6 +427,9 @@ int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz)
 	init_rwsem(&mi->mi_sem);
 	inode->i_private = mi;
 
+	if (inode->i_ino == NILFS_SUFILE_INO)
+		lockdep_set_class(&mi->mi_sem, &nilfs_mdt_mi_sufile_lock_key);
+
 	inode->i_mode = S_IFREG;
 	mapping_set_gfp_mask(inode->i_mapping, gfp_mask);
 	inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi;
Signature · 6 lines
1.9.0

--
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
#38 lore raw

PATCH 1/4 nilfs-utils: remove reliance on sui_nblocks to read segment

In reply to a message not in the archive

Since sui_nblocks is reused to represent the number of live blocks in a segment it cannot be used any more to mark the end of the segment. Instead the sequence number of the partial segments is checked. The sequence number of partial segments should all be the same. The usual CRC checks should be enough to reliably determine the end of a segment.

---
 include/nilfs.h | 1 +
 lib/gc.c        | 5 ++---
 lib/nilfs.c     | 4 +++-
 3 files changed, 6 insertions(+), 4 deletions(-)
include/nilfs.h +1 -0
index fab8ff2..05cfe3b 100644
@@ -185,6 +185,7 @@ struct nilfs_psegment {
 	size_t p_maxblocks;
 	size_t p_blksize;
 	__u32 p_seed;
+	__u64 p_seq;
 };
 
 /**
lib/gc.c +2 -3
index 453acf2..a165a5c 100644
@@ -273,9 +273,8 @@ static ssize_t nilfs_acc_blocks(struct nilfs *nilfs,
 				return -1;
 			continue;
 		}
-		ret = nilfs_acc_blocks_segment(
-			nilfs, segnums[i], segment, si.sui_nblocks,
-			vdescv, bdescv);
+		ret = nilfs_acc_blocks_segment(nilfs, segnums[i], segment,
+			nilfs_get_blocks_per_segment(nilfs), vdescv, bdescv);
 		if (nilfs_put_segment(nilfs, segment) < 0 || ret < 0)
 			return -1;
 		i++;
lib/nilfs.c +3 -1
index 65bf7d5..e8f5c96 100644
@@ -900,7 +900,8 @@ static int nilfs_psegment_is_valid(const struct nilfs_psegment *pseg)
 {
 	int offset;
 
-	if (le32_to_cpu(pseg->p_segsum->ss_magic) != NILFS_SEGSUM_MAGIC)
+	if (le32_to_cpu(pseg->p_segsum->ss_magic) != NILFS_SEGSUM_MAGIC ||
+			le64_to_cpu(pseg->p_segsum->ss_seq) != pseg->p_seq)
 		return 0;
 
 	offset = sizeof(pseg->p_segsum->ss_datasum) +
@@ -928,6 +929,7 @@ void nilfs_psegment_init(struct nilfs_psegment *pseg, __u64 segnum,
 	pseg->p_seed = le32_to_cpu(nilfs->n_sb->s_crc_seed);
 
 	pseg->p_segsum = seg + blkoff * pseg->p_blksize;
+	pseg->p_seq = le64_to_cpu(pseg->p_segsum->ss_seq);
 	pseg->p_blocknr = pseg->p_segblocknr;
 }
 
Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): 36b7f57861b69c7fdb9d9e54a21df6f5c7f21061.1394966935.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#40 lore raw

PATCH 2/4 nilfs-utils: add cost-benefit and greedy policies

This patch implements the cost-benefit and greedy GC policies. These are well known policies for log-structured file systems [1].

* Greedy:
Select the segments with the most free space.
* Cost-Benefit:
Perform a cost-benefit analysis, whereby the free space gained is weighed against the cost of collecting the segment.

Since especially cost-benefit needed more information than was available in nilfs_suinfo, a few extra parameters were added to the policy callback function prototype. The policy threshold was removed, since it served no real purpose. The flag p_comparison was added to indicate how the importance values should be interpreted. For example for the timestamp policy smaller values mean older timestamps, which is better. For greedy and cost-benefit on the other hand higher values are better. nilfs_cleanerd_select_segments() was updated accordingly.

[1] Mendel Rosenblum and John K. Ousterhout. The design and implementa- tion of a log-structured file system. ACM Trans. Comput. Syst., 10(1):26–52, February 1992.

---
 include/nilfs2_fs.h       |   9 ++++-
 sbin/cleanerd/cldconfig.c | 100 +++++++++++++++++++++++++++++++++++++++++++---
 sbin/cleanerd/cldconfig.h |  18 +++++----
 sbin/cleanerd/cleanerd.c  |  56 ++++++++++++++++----------
 4 files changed, 149 insertions(+), 34 deletions(-)
include/nilfs2_fs.h +8 -1
index a16ad4c..967c2af 100644
@@ -483,7 +483,7 @@ struct nilfs_dat_entry {
 	__le64 de_blocknr;
 	__le64 de_start;
 	__le64 de_end;
-	__le64 de_rsv;
+	__le64 de_ss;
 };
 
 /**
@@ -612,11 +612,13 @@ struct nilfs_cpfile_header {
  * @su_lastmod: last modified timestamp
  * @su_nblocks: number of blocks in segment
  * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
  */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;
 };
 
 /* segment usage flag */
@@ -659,6 +661,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(0);
+	su->su_lastdec = cpu_to_le64(0);
 }
 
 static inline int
@@ -690,11 +693,13 @@ struct nilfs_sufile_header {
  * @sui_lastmod: timestamp of last modification
  * @sui_nblocks: number of written blocks in segment
  * @sui_flags: segment usage flags
+ * @sui_lastdec: last decrement of sui_nblocks timestamp
  */
 struct nilfs_suinfo {
 	__u64 sui_lastmod;
 	__u32 sui_nblocks;
 	__u32 sui_flags;
+	__u64 sui_lastdec;
 };
 
 #define NILFS_SUINFO_FNS(flag, name)					\
@@ -732,6 +737,7 @@ enum {
 	NILFS_SUINFO_UPDATE_LASTMOD,
 	NILFS_SUINFO_UPDATE_NBLOCKS,
 	NILFS_SUINFO_UPDATE_FLAGS,
+	NILFS_SUINFO_UPDATE_LASTDEC,
 	__NR_NILFS_SUINFO_UPDATE_FIELDS,
 };
 
@@ -755,6 +761,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
 NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
 NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
 NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec)
 
 enum {
 	NILFS_CHECKPOINT,
sbin/cleanerd/cldconfig.c +95 -5

124 lines not on this page · raw message

sbin/cleanerd/cldconfig.h +11 -7
index 0a598d5..95d2fde 100644
@@ -30,16 +30,21 @@
 #include <sys/time.h>
 #include <syslog.h>
 
+struct nilfs;
+struct nilfs_sustat;
 struct nilfs_suinfo;
 
 /**
  * struct nilfs_selection_policy -
- * @p_importance:
- * @p_threshold:
+ * @p_importance: function to calculate the importance for the policy
+ * @p_comparison: flag that indicates how to sort the importance
  */
 struct nilfs_selection_policy {
-	unsigned long long (*p_importance)(const struct nilfs_suinfo *);
-	unsigned long long p_threshold;
+	unsigned long long (*p_importance)(struct nilfs *nilfs,
+					   const struct nilfs_sustat *sustat,
+					   const struct nilfs_suinfo *,
+					   __u64 prottime);
+	int p_comparison;
 };
 
 /**
@@ -113,7 +118,8 @@ struct nilfs_cldconfig {
 
 #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE	\
 			nilfs_cldconfig_selection_policy_timestamp
-#define NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD	0
+#define NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER	0
+#define NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER	1
 #define NILFS_CLDCONFIG_PROTECTION_PERIOD		3600
 #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS		10
 #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS_UNIT		NILFS_SIZE_UNIT_PERCENT
@@ -135,8 +141,6 @@ struct nilfs_cldconfig {
 
 #define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX	32
 
-struct nilfs;
-
 int nilfs_cldconfig_read(struct nilfs_cldconfig *config, const char *path,
 			 struct nilfs *nilfs);
 
sbin/cleanerd/cleanerd.c +35 -21

95 lines not on this page · raw message

Signature · 6 lines
1.9.0

--
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

A message that is not in the archive (sent off-list or not yet received): cc43be2e6bba5367fd2982dc0df5255b884bdace.1394966935.git.andreas.rohner-hi6Y0CQ0nG0@public.gmane.org

#42 lore raw

Re: [PATCH 2/4] nilfs-utils: add cost-benefit and greedy policies

Quoted 382 lines · Andreas Rohner

This patch implements the cost-benefit and greedy GC policies. These are well known policies for log-structured file systems [1].

* Greedy:
Select the segments with the most free space.
* Cost-Benefit:
Perform a cost-benefit analysis, whereby the free space gained is weighed against the cost of collecting the segment.

Since especially cost-benefit needed more information than was available in nilfs_suinfo, a few extra parameters were added to the policy callback function prototype. The policy threshold was removed, since it served no real purpose. The flag p_comparison was added to indicate how the importance values should be interpreted. For example for the timestamp policy smaller values mean older timestamps, which is better. For greedy and cost-benefit on the other hand higher values are better. nilfs_cleanerd_select_segments() was updated accordingly.

[1] Mendel Rosenblum and John K. Ousterhout. The design and implementa- tion of a log-structured file system. ACM Trans. Comput. Syst., 10(1):26–52, February 1992.

---
 include/nilfs2_fs.h       |   9 ++++-
 sbin/cleanerd/cldconfig.c | 100 +++++++++++++++++++++++++++++++++++++++++++---
 sbin/cleanerd/cldconfig.h |  18 +++++----
 sbin/cleanerd/cleanerd.c  |  56 ++++++++++++++++----------
 4 files changed, 149 insertions(+), 34 deletions(-)
include/nilfs2_fs.h +8 -1
index a16ad4c..967c2af 100644
@@ -483,7 +483,7 @@ struct nilfs_dat_entry {
 	__le64 de_blocknr;
 	__le64 de_start;
 	__le64 de_end;
-	__le64 de_rsv;
+	__le64 de_ss;
 };
 
 /**
@@ -612,11 +612,13 @@ struct nilfs_cpfile_header {
  * @su_lastmod: last modified timestamp
  * @su_nblocks: number of blocks in segment
  * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
  */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;
 };
 
 /* segment usage flag */
@@ -659,6 +661,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(0);
+	su->su_lastdec = cpu_to_le64(0);
 }
 
 static inline int
@@ -690,11 +693,13 @@ struct nilfs_sufile_header {
  * @sui_lastmod: timestamp of last modification
  * @sui_nblocks: number of written blocks in segment
  * @sui_flags: segment usage flags
+ * @sui_lastdec: last decrement of sui_nblocks timestamp
  */
 struct nilfs_suinfo {
 	__u64 sui_lastmod;
 	__u32 sui_nblocks;
 	__u32 sui_flags;
+	__u64 sui_lastdec;
 };
 
 #define NILFS_SUINFO_FNS(flag, name)					\
@@ -732,6 +737,7 @@ enum {
 	NILFS_SUINFO_UPDATE_LASTMOD,
 	NILFS_SUINFO_UPDATE_NBLOCKS,
 	NILFS_SUINFO_UPDATE_FLAGS,
+	NILFS_SUINFO_UPDATE_LASTDEC,
 	__NR_NILFS_SUINFO_UPDATE_FIELDS,
 };
 
@@ -755,6 +761,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
 NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
 NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
 NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec)
 
 enum {
 	NILFS_CHECKPOINT,
sbin/cleanerd/cldconfig.c +95 -5
index c8b197b..ade974a 100644
@@ -380,7 +380,10 @@ nilfs_cldconfig_handle_clean_check_interval(struct nilfs_cldconfig *config,
 }
 
 static unsigned long long
-nilfs_cldconfig_selection_policy_timestamp(const struct nilfs_suinfo *si)
+nilfs_cldconfig_selection_policy_timestamp(struct nilfs *nilfs,
+					   const struct nilfs_sustat *sustat,
+					   const struct nilfs_suinfo *si,
+					   __u64 prottime)
 {
 	return si->sui_lastmod;
 }
@@ -391,14 +394,101 @@ nilfs_cldconfig_handle_selection_policy_timestamp(struct nilfs_cldconfig *config
 {
 	config->cf_selection_policy.p_importance =
 		NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE;
-	config->cf_selection_policy.p_threshold =
-		NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD;
+	config->cf_selection_policy.p_comparison =
+			NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER;
+	return 0;
+}
+
+static unsigned long long
+nilfs_cldconfig_selection_policy_greedy(struct nilfs *nilfs,
+				        const struct nilfs_sustat *sustat,
+				        const struct nilfs_suinfo *si,
+				        __u64 prottime)
+{
+	__u32 value, max_blocks = nilfs_get_blocks_per_segment(nilfs);
+
+	if (max_blocks < si->sui_nblocks)
+		return 0;
+
+	value = max_blocks - si->sui_nblocks;
+
+	/*
+	 * the value of sui_nblocks is probably not accurate
+	 * because blocks inside the protection period are not
+	 * considered to be dead
+	 */
+	if (si->sui_lastdec >= prottime)
+		value >>= 4;
+
+	return value;
+}
+
+static int
+nilfs_cldconfig_handle_selection_policy_greedy(struct nilfs_cldconfig *config,
+					       char **tokens, size_t ntoks)
+{
+	config->cf_selection_policy.p_importance =
+			nilfs_cldconfig_selection_policy_greedy;
+	config->cf_selection_policy.p_comparison =
+			NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER;
+	return 0;
+}
+
+static unsigned long long
+nilfs_cldconfig_selection_policy_cost_benefit(struct nilfs *nilfs,
+					      const struct nilfs_sustat *sustat,
+					      const struct nilfs_suinfo *si,
+					      __u64 prottime)
+{
+	__u32 free_blocks, cleaning_cost;
+	unsigned long long value, age;
+
+	free_blocks = nilfs_get_blocks_per_segment(nilfs) - si->sui_nblocks;
+	/* read the whole segment + write the live blocks */
+	cleaning_cost = 2 * si->sui_nblocks;
+	/*
+	 * multiply by 1000 to convert age to milliseconds
+	 * (higher precision for division)
+	 */
+	age = (sustat->ss_nongc_ctime - si->sui_lastmod) * 1000;
+
+	if (sustat->ss_nongc_ctime < si->sui_lastmod)
+		return 0;
+
+	if (cleaning_cost == 0)
+		cleaning_cost = 1;
+
+
+	value = (age * free_blocks) / cleaning_cost;
+
+	/*
+	 * the value of sui_nblocks is probably not accurate
+	 * because blocks inside the protection period are not
+	 * considered to be dead
+	 */
+	if (si->sui_lastdec >= prottime)
+		value >>= 4;
+
+	return value;
+}
+
+static int
+nilfs_cldconfig_handle_selection_policy_cost_benefit(
+						struct nilfs_cldconfig *config,
+						char **tokens, size_t ntoks)
+{
+	config->cf_selection_policy.p_importance =
+			nilfs_cldconfig_selection_policy_cost_benefit;
+	config->cf_selection_policy.p_comparison =
+			NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER;
 	return 0;
 }
 
 static const struct nilfs_cldconfig_polhandle
 nilfs_cldconfig_polhandle_table[] = {
 	{"timestamp",	nilfs_cldconfig_handle_selection_policy_timestamp},
+	{"greedy",	nilfs_cldconfig_handle_selection_policy_greedy},
+	{"cost-benefit", nilfs_cldconfig_handle_selection_policy_cost_benefit},
 };
 
 #define NILFS_CLDCONFIG_NPOLHANDLES			\
@@ -688,8 +778,8 @@ static void nilfs_cldconfig_set_default(struct nilfs_cldconfig *config,
 
 	config->cf_selection_policy.p_importance =
 		NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE;
-	config->cf_selection_policy.p_threshold =
-		NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD;
+	config->cf_selection_policy.p_comparison =
+		NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER;
 	config->cf_protection_period.tv_sec = NILFS_CLDCONFIG_PROTECTION_PERIOD;
 	config->cf_protection_period.tv_usec = 0;
 
sbin/cleanerd/cldconfig.h +11 -7
index 0a598d5..95d2fde 100644
@@ -30,16 +30,21 @@
 #include <sys/time.h>
 #include <syslog.h>
 
+struct nilfs;
+struct nilfs_sustat;
 struct nilfs_suinfo;
 
 /**
  * struct nilfs_selection_policy -
- * @p_importance:
- * @p_threshold:
+ * @p_importance: function to calculate the importance for the policy
+ * @p_comparison: flag that indicates how to sort the importance
  */
 struct nilfs_selection_policy {
-	unsigned long long (*p_importance)(const struct nilfs_suinfo *);
-	unsigned long long p_threshold;
+	unsigned long long (*p_importance)(struct nilfs *nilfs,
+					   const struct nilfs_sustat *sustat,
+					   const struct nilfs_suinfo *,
+					   __u64 prottime);
+	int p_comparison;
 };
 
 /**
@@ -113,7 +118,8 @@ struct nilfs_cldconfig {
 
 #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE	\
 			nilfs_cldconfig_selection_policy_timestamp
-#define NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD	0
+#define NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER	0
+#define NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER	1
 #define NILFS_CLDCONFIG_PROTECTION_PERIOD		3600
 #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS		10
 #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS_UNIT		NILFS_SIZE_UNIT_PERCENT
@@ -135,8 +141,6 @@ struct nilfs_cldconfig {
 
 #define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX	32
 
-struct nilfs;
-
 int nilfs_cldconfig_read(struct nilfs_cldconfig *config, const char *path,
 			 struct nilfs *nilfs);
 
sbin/cleanerd/cleanerd.c +35 -21
index 17de87b..8df3a07 100644
@@ -417,7 +417,7 @@ static void nilfs_cleanerd_destroy(struct nilfs_cleanerd *cleanerd)
 	free(cleanerd);
 }
 
-static int nilfs_comp_segimp(const void *elem1, const void *elem2)
+static int nilfs_comp_segimp_asc(const void *elem1, const void *elem2)
 {
 	const struct nilfs_segimp *segimp1 = elem1, *segimp2 = elem2;
 
@@ -429,6 +429,18 @@ static int nilfs_comp_segimp(const void *elem1, const void *elem2)
 	return (segimp1->si_segnum < segimp2->si_segnum) ? -1 : 1;
 }
 
+static int nilfs_comp_segimp_desc(const void *elem1, const void *elem2)
+{
+	const struct nilfs_segimp *segimp1 = elem1, *segimp2 = elem2;
+
+	if (segimp1->si_importance > segimp2->si_importance)
+		return -1;
+	else if (segimp1->si_importance < segimp2->si_importance)
+		return 1;
+
+	return (segimp1->si_segnum < segimp2->si_segnum) ? -1 : 1;
+}
+
 static int nilfs_cleanerd_automatic_suspend(struct nilfs_cleanerd *cleanerd)
 {
 	return cleanerd->config.cf_min_clean_segments > 0;
@@ -579,7 +591,7 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 	__u64 segnum;
 	size_t count, nsegs;
 	ssize_t nssegs, n;
-	unsigned long long imp, thr;
+	unsigned long long imp;
 	int i;
 
 	nsegs = nilfs_cleanerd_ncleansegs(cleanerd);
@@ -600,11 +612,8 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 	prottime = tv2.tv_sec;
 	oldest = tv.tv_sec;
 
-	/* The segments that have larger importance than thr are not
-	 * selected. */
-	thr = (config->cf_selection_policy.p_threshold != 0) ?
-		config->cf_selection_policy.p_threshold :
-		sustat->ss_nongc_ctime;
+	/* sui_lastdec may not be set by nilfs_get_suinfo */
+	memset(si, 0, sizeof(si));
 
 	for (segnum = 0; segnum < sustat->ss_nsegs; segnum += n) {
 		count = min_t(__u64, sustat->ss_nsegs - segnum,
@@ -615,22 +624,23 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 			goto out;
 		}
 		for (i = 0; i < n; i++) {
-			if (!nilfs_suinfo_reclaimable(&si[i]))
+			if (!nilfs_suinfo_reclaimable(&si[i]) ||
+				si[i].sui_lastmod >= sustat->ss_nongc_ctime)
 				continue;
 
-			imp = config->cf_selection_policy.p_importance(&si[i]);
-			if (imp < thr) {
-				if (si[i].sui_lastmod < oldest)
-					oldest = si[i].sui_lastmod;
-				if (si[i].sui_lastmod < prottime) {
-					sm = nilfs_vector_get_new_element(smv);
-					if (sm == NULL) {
-						nssegs = -1;
-						goto out;
-					}
-					sm->si_segnum = segnum + i;
-					sm->si_importance = imp;
+			imp = config->cf_selection_policy.p_importance(nilfs,
+					sustat, &si[i], prottime);
+
+			if (si[i].sui_lastmod < oldest)
+				oldest = si[i].sui_lastmod;
+			if (si[i].sui_lastmod < prottime) {
+				sm = nilfs_vector_get_new_element(smv);
+				if (sm == NULL) {
+					nssegs = -1;
+					goto out;
 				}
+				sm->si_segnum = segnum + i;
+				sm->si_importance = imp;
 			}
 		}
 		if (n == 0) {
@@ -642,7 +652,11 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 			break;
 		}
 	}
-	nilfs_vector_sort(smv, nilfs_comp_segimp);
+	if (config->cf_selection_policy.p_comparison ==
+			NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER)
+		nilfs_vector_sort(smv, nilfs_comp_segimp_asc);
+	else
+		nilfs_vector_sort(smv, nilfs_comp_segimp_desc);
 
 	nssegs = (nilfs_vector_get_size(smv) < nsegs) ?
 		nilfs_vector_get_size(smv) : nsegs;
Signature · 1 line
1.9.0

scripts/checkpatch.pl detected the following coding style issues:

ERROR: code indent should use tabs where possible
#171: FILE: sbin/cleanerd/cldconfig.c:404:
+^I^I^I^I const struct nilfs_sustat *sustat,$

ERROR: code indent should use tabs where possible
#172: FILE: sbin/cleanerd/cldconfig.c:405:
+^I^I^I^I const struct nilfs_suinfo *si,$

ERROR: code indent should use tabs where possible
#173: FILE: sbin/cleanerd/cldconfig.c:406:
+^I^I^I^I __u64 prottime)$

Please mind it next time. (You don't have to resubmit the whole series now for this).

I would like to first understand this series, but I am very busy recently. (Also, I am still pending review of Vycheslav's xattr patchset.) So, let me go forward a little bit at a time.

Regards,
Ryusuke Konishi
--
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

A message that is not in the archive (sent off-list or not yet received): 20140316.215545.291456562.konishi.ryusuke-Zyj7fXuS5i5L9jVzuh4AOg@public.gmane.org

#44 lore raw

Re: [PATCH 2/4] nilfs-utils: add cost-benefit and greedy policies

Quoted 394 lines · Ryusuke Konishi
Quoted 382 lines · Andreas Rohner

This patch implements the cost-benefit and greedy GC policies. These are well known policies for log-structured file systems [1].

* Greedy:
Select the segments with the most free space.
* Cost-Benefit:
Perform a cost-benefit analysis, whereby the free space gained is weighed against the cost of collecting the segment.

Since especially cost-benefit needed more information than was available in nilfs_suinfo, a few extra parameters were added to the policy callback function prototype. The policy threshold was removed, since it served no real purpose. The flag p_comparison was added to indicate how the importance values should be interpreted. For example for the timestamp policy smaller values mean older timestamps, which is better. For greedy and cost-benefit on the other hand higher values are better. nilfs_cleanerd_select_segments() was updated accordingly.

[1] Mendel Rosenblum and John K. Ousterhout. The design and implementa- tion of a log-structured file system. ACM Trans. Comput. Syst., 10(1):26–52, February 1992.

---
 include/nilfs2_fs.h       |   9 ++++-
 sbin/cleanerd/cldconfig.c | 100 +++++++++++++++++++++++++++++++++++++++++++---
 sbin/cleanerd/cldconfig.h |  18 +++++----
 sbin/cleanerd/cleanerd.c  |  56 ++++++++++++++++----------
 4 files changed, 149 insertions(+), 34 deletions(-)
include/nilfs2_fs.h +8 -1
index a16ad4c..967c2af 100644
@@ -483,7 +483,7 @@ struct nilfs_dat_entry {
 	__le64 de_blocknr;
 	__le64 de_start;
 	__le64 de_end;
-	__le64 de_rsv;
+	__le64 de_ss;
 };
 
 /**
@@ -612,11 +612,13 @@ struct nilfs_cpfile_header {
  * @su_lastmod: last modified timestamp
  * @su_nblocks: number of blocks in segment
  * @su_flags: flags
+ * @su_lastdec: last decrement of su_nblocks timestamp
  */
 struct nilfs_segment_usage {
 	__le64 su_lastmod;
 	__le32 su_nblocks;
 	__le32 su_flags;
+	__le64 su_lastdec;
 };
 
 /* segment usage flag */
@@ -659,6 +661,7 @@ nilfs_segment_usage_set_clean(struct nilfs_segment_usage *su)
 	su->su_lastmod = cpu_to_le64(0);
 	su->su_nblocks = cpu_to_le32(0);
 	su->su_flags = cpu_to_le32(0);
+	su->su_lastdec = cpu_to_le64(0);
 }
 
 static inline int
@@ -690,11 +693,13 @@ struct nilfs_sufile_header {
  * @sui_lastmod: timestamp of last modification
  * @sui_nblocks: number of written blocks in segment
  * @sui_flags: segment usage flags
+ * @sui_lastdec: last decrement of sui_nblocks timestamp
  */
 struct nilfs_suinfo {
 	__u64 sui_lastmod;
 	__u32 sui_nblocks;
 	__u32 sui_flags;
+	__u64 sui_lastdec;
 };
 
 #define NILFS_SUINFO_FNS(flag, name)					\
@@ -732,6 +737,7 @@ enum {
 	NILFS_SUINFO_UPDATE_LASTMOD,
 	NILFS_SUINFO_UPDATE_NBLOCKS,
 	NILFS_SUINFO_UPDATE_FLAGS,
+	NILFS_SUINFO_UPDATE_LASTDEC,
 	__NR_NILFS_SUINFO_UPDATE_FIELDS,
 };
 
@@ -755,6 +761,7 @@ nilfs_suinfo_update_##name(const struct nilfs_suinfo_update *sup)	\
 NILFS_SUINFO_UPDATE_FNS(LASTMOD, lastmod)
 NILFS_SUINFO_UPDATE_FNS(NBLOCKS, nblocks)
 NILFS_SUINFO_UPDATE_FNS(FLAGS, flags)
+NILFS_SUINFO_UPDATE_FNS(LASTDEC, lastdec)
 
 enum {
 	NILFS_CHECKPOINT,
sbin/cleanerd/cldconfig.c +95 -5
index c8b197b..ade974a 100644
@@ -380,7 +380,10 @@ nilfs_cldconfig_handle_clean_check_interval(struct nilfs_cldconfig *config,
 }
 
 static unsigned long long
-nilfs_cldconfig_selection_policy_timestamp(const struct nilfs_suinfo *si)
+nilfs_cldconfig_selection_policy_timestamp(struct nilfs *nilfs,
+					   const struct nilfs_sustat *sustat,
+					   const struct nilfs_suinfo *si,
+					   __u64 prottime)
 {
 	return si->sui_lastmod;
 }
@@ -391,14 +394,101 @@ nilfs_cldconfig_handle_selection_policy_timestamp(struct nilfs_cldconfig *config
 {
 	config->cf_selection_policy.p_importance =
 		NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE;
-	config->cf_selection_policy.p_threshold =
-		NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD;
+	config->cf_selection_policy.p_comparison =
+			NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER;
+	return 0;
+}
+
+static unsigned long long
+nilfs_cldconfig_selection_policy_greedy(struct nilfs *nilfs,
+				        const struct nilfs_sustat *sustat,
+				        const struct nilfs_suinfo *si,
+				        __u64 prottime)
+{
+	__u32 value, max_blocks = nilfs_get_blocks_per_segment(nilfs);
+
+	if (max_blocks < si->sui_nblocks)
+		return 0;
+
+	value = max_blocks - si->sui_nblocks;
+
+	/*
+	 * the value of sui_nblocks is probably not accurate
+	 * because blocks inside the protection period are not
+	 * considered to be dead
+	 */
+	if (si->sui_lastdec >= prottime)
+		value >>= 4;
+
+	return value;
+}
+
+static int
+nilfs_cldconfig_handle_selection_policy_greedy(struct nilfs_cldconfig *config,
+					       char **tokens, size_t ntoks)
+{
+	config->cf_selection_policy.p_importance =
+			nilfs_cldconfig_selection_policy_greedy;
+	config->cf_selection_policy.p_comparison =
+			NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER;
+	return 0;
+}
+
+static unsigned long long
+nilfs_cldconfig_selection_policy_cost_benefit(struct nilfs *nilfs,
+					      const struct nilfs_sustat *sustat,
+					      const struct nilfs_suinfo *si,
+					      __u64 prottime)
+{
+	__u32 free_blocks, cleaning_cost;
+	unsigned long long value, age;
+
+	free_blocks = nilfs_get_blocks_per_segment(nilfs) - si->sui_nblocks;
+	/* read the whole segment + write the live blocks */
+	cleaning_cost = 2 * si->sui_nblocks;
+	/*
+	 * multiply by 1000 to convert age to milliseconds
+	 * (higher precision for division)
+	 */
+	age = (sustat->ss_nongc_ctime - si->sui_lastmod) * 1000;
+
+	if (sustat->ss_nongc_ctime < si->sui_lastmod)
+		return 0;
+
+	if (cleaning_cost == 0)
+		cleaning_cost = 1;
+
+
+	value = (age * free_blocks) / cleaning_cost;
+
+	/*
+	 * the value of sui_nblocks is probably not accurate
+	 * because blocks inside the protection period are not
+	 * considered to be dead
+	 */
+	if (si->sui_lastdec >= prottime)
+		value >>= 4;
+
+	return value;
+}
+
+static int
+nilfs_cldconfig_handle_selection_policy_cost_benefit(
+						struct nilfs_cldconfig *config,
+						char **tokens, size_t ntoks)
+{
+	config->cf_selection_policy.p_importance =
+			nilfs_cldconfig_selection_policy_cost_benefit;
+	config->cf_selection_policy.p_comparison =
+			NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER;
 	return 0;
 }
 
 static const struct nilfs_cldconfig_polhandle
 nilfs_cldconfig_polhandle_table[] = {
 	{"timestamp",	nilfs_cldconfig_handle_selection_policy_timestamp},
+	{"greedy",	nilfs_cldconfig_handle_selection_policy_greedy},
+	{"cost-benefit", nilfs_cldconfig_handle_selection_policy_cost_benefit},
 };
 
 #define NILFS_CLDCONFIG_NPOLHANDLES			\
@@ -688,8 +778,8 @@ static void nilfs_cldconfig_set_default(struct nilfs_cldconfig *config,
 
 	config->cf_selection_policy.p_importance =
 		NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE;
-	config->cf_selection_policy.p_threshold =
-		NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD;
+	config->cf_selection_policy.p_comparison =
+		NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER;
 	config->cf_protection_period.tv_sec = NILFS_CLDCONFIG_PROTECTION_PERIOD;
 	config->cf_protection_period.tv_usec = 0;
 
sbin/cleanerd/cldconfig.h +11 -7
index 0a598d5..95d2fde 100644
@@ -30,16 +30,21 @@
 #include <sys/time.h>
 #include <syslog.h>
 
+struct nilfs;
+struct nilfs_sustat;
 struct nilfs_suinfo;
 
 /**
  * struct nilfs_selection_policy -
- * @p_importance:
- * @p_threshold:
+ * @p_importance: function to calculate the importance for the policy
+ * @p_comparison: flag that indicates how to sort the importance
  */
 struct nilfs_selection_policy {
-	unsigned long long (*p_importance)(const struct nilfs_suinfo *);
-	unsigned long long p_threshold;
+	unsigned long long (*p_importance)(struct nilfs *nilfs,
+					   const struct nilfs_sustat *sustat,
+					   const struct nilfs_suinfo *,
+					   __u64 prottime);
+	int p_comparison;
 };
 
 /**
@@ -113,7 +118,8 @@ struct nilfs_cldconfig {
 
 #define NILFS_CLDCONFIG_SELECTION_POLICY_IMPORTANCE	\
 			nilfs_cldconfig_selection_policy_timestamp
-#define NILFS_CLDCONFIG_SELECTION_POLICY_THRESHOLD	0
+#define NILFS_CLDCONFIG_SELECTION_POLICY_BIGGER_IS_BETTER	0
+#define NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER	1
 #define NILFS_CLDCONFIG_PROTECTION_PERIOD		3600
 #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS		10
 #define NILFS_CLDCONFIG_MIN_CLEAN_SEGMENTS_UNIT		NILFS_SIZE_UNIT_PERCENT
@@ -135,8 +141,6 @@ struct nilfs_cldconfig {
 
 #define NILFS_CLDCONFIG_NSEGMENTS_PER_CLEAN_MAX	32
 
-struct nilfs;
-
 int nilfs_cldconfig_read(struct nilfs_cldconfig *config, const char *path,
 			 struct nilfs *nilfs);
 
sbin/cleanerd/cleanerd.c +35 -21
index 17de87b..8df3a07 100644
@@ -417,7 +417,7 @@ static void nilfs_cleanerd_destroy(struct nilfs_cleanerd *cleanerd)
 	free(cleanerd);
 }
 
-static int nilfs_comp_segimp(const void *elem1, const void *elem2)
+static int nilfs_comp_segimp_asc(const void *elem1, const void *elem2)
 {
 	const struct nilfs_segimp *segimp1 = elem1, *segimp2 = elem2;
 
@@ -429,6 +429,18 @@ static int nilfs_comp_segimp(const void *elem1, const void *elem2)
 	return (segimp1->si_segnum < segimp2->si_segnum) ? -1 : 1;
 }
 
+static int nilfs_comp_segimp_desc(const void *elem1, const void *elem2)
+{
+	const struct nilfs_segimp *segimp1 = elem1, *segimp2 = elem2;
+
+	if (segimp1->si_importance > segimp2->si_importance)
+		return -1;
+	else if (segimp1->si_importance < segimp2->si_importance)
+		return 1;
+
+	return (segimp1->si_segnum < segimp2->si_segnum) ? -1 : 1;
+}
+
 static int nilfs_cleanerd_automatic_suspend(struct nilfs_cleanerd *cleanerd)
 {
 	return cleanerd->config.cf_min_clean_segments > 0;
@@ -579,7 +591,7 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 	__u64 segnum;
 	size_t count, nsegs;
 	ssize_t nssegs, n;
-	unsigned long long imp, thr;
+	unsigned long long imp;
 	int i;
 
 	nsegs = nilfs_cleanerd_ncleansegs(cleanerd);
@@ -600,11 +612,8 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 	prottime = tv2.tv_sec;
 	oldest = tv.tv_sec;
 
-	/* The segments that have larger importance than thr are not
-	 * selected. */
-	thr = (config->cf_selection_policy.p_threshold != 0) ?
-		config->cf_selection_policy.p_threshold :
-		sustat->ss_nongc_ctime;
+	/* sui_lastdec may not be set by nilfs_get_suinfo */
+	memset(si, 0, sizeof(si));
 
 	for (segnum = 0; segnum < sustat->ss_nsegs; segnum += n) {
 		count = min_t(__u64, sustat->ss_nsegs - segnum,
@@ -615,22 +624,23 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 			goto out;
 		}
 		for (i = 0; i < n; i++) {
-			if (!nilfs_suinfo_reclaimable(&si[i]))
+			if (!nilfs_suinfo_reclaimable(&si[i]) ||
+				si[i].sui_lastmod >= sustat->ss_nongc_ctime)
 				continue;
 
-			imp = config->cf_selection_policy.p_importance(&si[i]);
-			if (imp < thr) {
-				if (si[i].sui_lastmod < oldest)
-					oldest = si[i].sui_lastmod;
-				if (si[i].sui_lastmod < prottime) {
-					sm = nilfs_vector_get_new_element(smv);
-					if (sm == NULL) {
-						nssegs = -1;
-						goto out;
-					}
-					sm->si_segnum = segnum + i;
-					sm->si_importance = imp;
+			imp = config->cf_selection_policy.p_importance(nilfs,
+					sustat, &si[i], prottime);
+
+			if (si[i].sui_lastmod < oldest)
+				oldest = si[i].sui_lastmod;
+			if (si[i].sui_lastmod < prottime) {
+				sm = nilfs_vector_get_new_element(smv);
+				if (sm == NULL) {
+					nssegs = -1;
+					goto out;
 				}
+				sm->si_segnum = segnum + i;
+				sm->si_importance = imp;
 			}
 		}
 		if (n == 0) {
@@ -642,7 +652,11 @@ nilfs_cleanerd_select_segments(struct nilfs_cleanerd *cleanerd,
 			break;
 		}
 	}
-	nilfs_vector_sort(smv, nilfs_comp_segimp);
+	if (config->cf_selection_policy.p_comparison ==
+			NILFS_CLDCONFIG_SELECTION_POLICY_SMALLER_IS_BETTER)
+		nilfs_vector_sort(smv, nilfs_comp_segimp_asc);
+	else
+		nilfs_vector_sort(smv, nilfs_comp_segimp_desc);
 
 	nssegs = (nilfs_vector_get_size(smv) < nsegs) ?
 		nilfs_vector_get_size(smv) : nsegs;
Signature · 1 line
1.9.0

scripts/checkpatch.pl detected the following coding style issues:

ERROR: code indent should use tabs where possible
#171: FILE: sbin/cleanerd/cldconfig.c:404:
+^I^I^I^I const struct nilfs_sustat *sustat,$

ERROR: code indent should use tabs where possible
#172: FILE: sbin/cleanerd/cldconfig.c:405:
+^I^I^I^I const struct nilfs_suinfo *si,$

Quoted 7 lines

ERROR: code indent should use tabs where possible
#173: FILE: sbin/cleanerd/cldconfig.c:406:
+^I^I^I^I __u64 prottime)$

Please mind it next time. (You don't have to resubmit the whole series now for this).

Normally I execute checkpatch.pl automatically via the pre-commit hook. For some reason the pre-commit hook got overwritten in my local repo. I am sorry for that.

Quoted 3 lines

I would like to first understand this series, but I am very busy recently. (Also, I am still pending review of Vycheslav's xattr patchset.) So, let me go forward a little bit at a time.

Ok no problem.

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

#45 lore raw

PATCH 3/4 nilfs-utils: add support for nilfs_clean_snapshot_flags()

In reply to a message not in the archive

This ioctl enables the userspace GC to perform a cleanup operation after setting the number of blocks with NILFS_IOCTL_SET_SUINFO. It sets DAT entries with de_ss values of NILFS_CNO_MAX to 0. NILFS_CNO_MAX indicates, that the corresponding block belongs to some snapshot, but was already decremented by a previous deletion operation. If the segment usage info is changed with NILFS_IOCTL_SET_SUINFO and the number of blocks is updated, then these blocks would never be decremented and there are scenarios where the corresponding segments would starve (never be cleaned). To prevent that the value of de_ss must be set to 0, so that it can be decremented again, should the snapshot be deleted in the future.

---
 include/nilfs.h     |  2 ++
 include/nilfs2_fs.h |  2 ++
 lib/gc.c            |  6 +++++-
 lib/nilfs.c         | 23 +++++++++++++++++++++++
 4 files changed, 32 insertions(+), 1 deletion(-)
include/nilfs.h +2 -0
index 05cfe3b..bd134be 100644
@@ -313,6 +313,8 @@ ssize_t nilfs_get_bdescs(const struct nilfs *, struct nilfs_bdesc *, size_t);
 int nilfs_clean_segments(struct nilfs *, struct nilfs_vdesc *, size_t,
 			 struct nilfs_period *, size_t, __u64 *, size_t,
 			 struct nilfs_bdesc *, size_t, __u64 *, size_t);
+int nilfs_clean_snapshot_flags(struct nilfs *nilfs,
+			       struct nilfs_vdesc *vdescs, size_t nvdescs);
 int nilfs_sync(const struct nilfs *, nilfs_cno_t *);
 int nilfs_resize(struct nilfs *nilfs, off_t size);
 int nilfs_set_alloc_range(struct nilfs *nilfs, off_t start, off_t end);
include/nilfs2_fs.h +2 -0
index 967c2af..cb02739 100644
@@ -918,5 +918,7 @@ struct nilfs_bdesc {
 	_IOW(NILFS_IOCTL_IDENT, 0x8C, __u64[2])
 #define NILFS_IOCTL_SET_SUINFO  \
 	_IOW(NILFS_IOCTL_IDENT, 0x8D, struct nilfs_argv)
+#define NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS  \
+	_IOW(NILFS_IOCTL_IDENT, 0x8F, struct nilfs_argv)
 
 #endif	/* _LINUX_NILFS_FS_H */
lib/gc.c +5 -1
index a165a5c..2338174 100644
@@ -762,8 +762,12 @@ int nilfs_xreclaim_segment(struct nilfs *nilfs,
 
 		ret = nilfs_set_suinfo(nilfs, nilfs_vector_get_data(supv), n);
 
-		if (ret == 0)
+		if (ret == 0) {
+			ret = nilfs_clean_snapshot_flags(nilfs,
+					nilfs_vector_get_data(vdescv),
+					nilfs_vector_get_size(vdescv));
 			goto out_lock;
+		}
 
 		if (ret < 0 && errno != ENOTTY) {
 			nilfs_gc_logger(LOG_ERR, "cannot set suinfo: %s",
lib/nilfs.c +23 -0
index e8f5c96..b909a23 100644
@@ -743,6 +743,29 @@ int nilfs_clean_segments(struct nilfs *nilfs,
 }
 
 /**
+ * nilfs_clean_snapshot_flags - cleanup snapshot flags after set_suinfo
+ * @nilfs: nilfs object
+ * @vdescs: array of nilfs_vdesc structs to specify live blocks
+ * @nvdescs: size of @vdescs array (number of items)
+ */
+int nilfs_clean_snapshot_flags(struct nilfs *nilfs,
+			       struct nilfs_vdesc *vdescs, size_t nvdescs)
+{
+	struct nilfs_argv argv;
+
+	if (nilfs->n_iocfd < 0) {
+		errno = EBADF;
+		return -1;
+	}
+
+	memset(&argv, 0, sizeof(struct nilfs_argv));
+	argv.v_base = (unsigned long)vdescs;
+	argv.v_nmembs = nvdescs;
+	argv.v_size = sizeof(struct nilfs_vdesc);
+	return ioctl(nilfs->n_iocfd, NILFS_IOCTL_CLEAN_SNAPSHOT_FLAGS, &argv);
+}
+
+/**
  * nilfs_sync - sync a NILFS file system
  * @nilfs: nilfs object
  * @cnop: buffer to store the latest checkpoint number in
Signature · 6 lines
1.9.0

--
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
#46 lore raw

PATCH 4/4 nilfs-utils: add extra flags to nilfs_vdesc and update sui_nblocks

In reply to a message not in the archive

This patch adds extra flags to nilfs_vdesc that indicate the reason for which a particular block is considered alive. If it is because of a snapshot, then the snapshot flag is set, if it is because of the protection period, then that flag is set.

This information is useful to determine the number of live blocks in a segment. If a block is part of a snapshot, it is counted as alive, if it is alive because of the protection period it is counted as reclaimable. These flags are used both in userspace and by the kernel.

Additionally this patch adds code that calculates the correct number of live blocks per segment if nilfs_set_suinfo() is used.

---
 include/nilfs.h     |  6 +++++
 include/nilfs2_fs.h | 52 +++++++++++++++++++++++++++++++++++++--
 lib/gc.c            | 71 +++++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 119 insertions(+), 10 deletions(-)
include/nilfs.h +6 -0
index bd134be..3585f6b 100644
@@ -329,4 +329,10 @@ static inline __u32 nilfs_get_blocks_per_segment(const struct nilfs *nilfs)
 	return le32_to_cpu(nilfs->n_sb->s_blocks_per_segment);
 }
 
+static inline __u64
+nilfs_get_segnum_of_block(const struct nilfs *nilfs, sector_t blocknr)
+{
+	return blocknr / nilfs_get_blocks_per_segment(nilfs);
+}
+
 #endif	/* NILFS_H */
include/nilfs2_fs.h +50 -2

66 lines not on this page · raw message

lib/gc.c +63 -8

134 lines not on this page · raw message

Signature · 6 lines
1.9.0

--
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
#47 lore raw
In reply to a message not in the archive
Quoted 6 lines · Andreas Rohner

Hi,

This patch set implements the tracking of live blocks in segments. This information is crucial in implementing better GC policies, because now the policies can make informed decisions about which segments have the biggest number of reclaimable blocks.

IMPORTANT:
I forgot to mention, that the patches are based on linux-next/master, because they rely on previous patches that aren't in master yet.

br,
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

A message that is not in the archive (sent off-list or not yet received): [email protected]

#49 lore raw
Quoted 12 lines · Andreas Rohner
Quoted 6 lines · Andreas Rohner

Hi,

This patch set implements the tracking of live blocks in segments. This information is crucial in implementing better GC policies, because now the policies can make informed decisions about which segments have the biggest number of reclaimable blocks.

IMPORTANT:
I forgot to mention, that the patches are based on linux-next/master, because they rely on previous patches that aren't in master yet.

As far as I can see, some guys mention about it via [PATCH -next 0/6], for example. :)

With the best regards,
Vyacheslav Dubeyko.

--
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

A message that is not in the archive (sent off-list or not yet received): 3EC9549C-84A7-49B5-9BE1-34A7337BFFDC-yeENwD64cLxBDgjK7y7TUQ@public.gmane.org

#51 lore raw
Quoted 11 lines · Vyacheslav Dubeyko
Quoted 8 lines · Andreas Rohner
Quoted 6 lines · Andreas Rohner

Hi,

This patch set implements the tracking of live blocks in segments. This information is crucial in implementing better GC policies, because now the policies can make informed decisions about which segments have the biggest number of reclaimable blocks.

Quoted 6 lines
Quoted 4 lines

IMPORTANT:
I forgot to mention, that the patches are based on linux-next/master, because they rely on previous patches that aren't in master yet.

As far as I can see, some guys mention about it via [PATCH -next 0/6], for example. :)

Thanks! I didn't know that. I will keep it in mind for next time.

br,
Andreas Rohner

Quoted 4 lines

With the best regards,
Vyacheslav Dubeyko.

--
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