From: amir73il@users.sourceforge.net
To: linux-ext4@vger.kernel.org
Cc: tytso@mit.edu, lczerner@redhat.com,
Amir Goldstein <amir73il@users.sf.net>,
Yongqiang Yang <xiaoqiangnk@gmail.com>
Subject: [PATCH v1 28/36] ext4: snapshot list - read through to previous snapshot
Date: Tue, 7 Jun 2011 18:07:55 +0300 [thread overview]
Message-ID: <1307459283-22130-29-git-send-email-amir73il@users.sourceforge.net> (raw)
In-Reply-To: <1307459283-22130-1-git-send-email-amir73il@users.sourceforge.net>
From: Amir Goldstein <amir73il@users.sf.net>
On snapshot page read, the function ext4_get_block() is called
to map the page to a disk block. If the page is not mapped in the
snapshot file, the newer snapshots on the list are checked and the
oldest found mapping is returned. If the page is not mapped in any of
the newer snapshots, a direct mapping to the block device is returned.
Signed-off-by: Amir Goldstein <amir73il@users.sf.net>
Signed-off-by: Yongqiang Yang <xiaoqiangnk@gmail.com>
---
fs/ext4/snapshot_inode.c | 74 +++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 73 insertions(+), 1 deletions(-)
diff --git a/fs/ext4/snapshot_inode.c b/fs/ext4/snapshot_inode.c
index 74b455d..a97411e 100644
--- a/fs/ext4/snapshot_inode.c
+++ b/fs/ext4/snapshot_inode.c
@@ -46,12 +46,62 @@
* in which case 'prev_snapshot' is pointed to the previous snapshot
* on the list or set to NULL to indicate read through to block device.
*/
+/*
+ * In-memory snapshot list manipulation is protected by snapshot_mutex.
+ * In this function we read the in-memory snapshot list without holding
+ * snapshot_mutex, because we don't want to slow down snapshot read performance.
+ * Following is a proof, that even though we don't hold snapshot_mutex here,
+ * reading the list is safe from races with snapshot list delete and add (take).
+ *
+ * Proof of no race with snapshot delete:
+ * --------------------------------------
+ * We get here only when reading from an enabled snapshot or when reading
+ * through from an enabled snapshot to a newer snapshot. Snapshot delete
+ * operation is only allowed for a disabled snapshot, when no older enabled
+ * snapshot exists (i.e., the deleted snapshot in not 'in-use'). Hence,
+ * read through is safe from races with snapshot list delete operations.
+ *
+ * Proof of no race with snapshot take:
+ * ------------------------------------
+ * Snapshot B take is composed of the following steps:
+ * ext4_snapshot_create():
+ * - Add snapshot B to head of list (active_snapshot is A).
+ * - Allocate and copy snapshot B initial blocks.
+ * ext4_snapshot_take():
+ * - Freeze FS
+ * - Clear snapshot A 'active' flag.
+ * - Set snapshot B 'list'+'active' flags.
+ * - Set snapshot B as active snapshot (active_snapshot=B).
+ * - Unfreeze FS
+ *
+ * Note that we do not need to rely on correct order of instructions within
+ * each of the functions above, but we can assume that Freeze FS will provide
+ * a strong barrier between adding B to list and the ops inside snapshot_take.
+ *
+ * When reading from snapshot A during snapshot B take, we have 2 cases:
+ * 1. is_active(A) is tested before setting active_snapshot=B -
+ * read through from A to block device.
+ * 2. is_active(A) is tested after setting active_snapshot=B -
+ * read through from A to B.
+ *
+ * When reading from snapshot B during snapshot B take, we have 2 cases:
+ * 1. B->flags and B->prev are read before adding B to list
+ * AND/OR before setting the 'list'+'active' flags -
+ * access to B denied.
+ * 2. is_active(B) is tested after setting active_snapshot=B
+ * AND/OR after setting the 'list'+'active' flags -
+ * read through from B to block device.
+ */
static int ext4_snapshot_get_block_access(struct inode *inode,
struct inode **prev_snapshot)
{
struct ext4_inode_info *ei = EXT4_I(inode);
unsigned long flags = ext4_get_snapstate_flags(inode);
+ struct list_head *prev = ei->i_snaplist.prev;
+ if (!(flags & 1UL<<EXT4_SNAPSTATE_LIST))
+ /* snapshot not on the list - read/write access denied */
+ return -EPERM;
*prev_snapshot = NULL;
if (ext4_snapshot_is_active(inode) ||
@@ -59,7 +109,23 @@ static int ext4_snapshot_get_block_access(struct inode *inode,
/* read through from active snapshot to block device */
return 0;
- return -EPERM;
+ if (prev == &ei->i_snaplist)
+ /* not on snapshots list? */
+ return -EIO;
+
+ if (prev == &EXT4_SB(inode->i_sb)->s_snapshot_list)
+ /* active snapshot not found on list? */
+ return -EIO;
+
+ /* read through to prev snapshot on the list */
+ ei = list_entry(prev, struct ext4_inode_info, i_snaplist);
+ *prev_snapshot = &ei->vfs_inode;
+
+ if (!ext4_snapshot_file(*prev_snapshot))
+ /* non snapshot file on the list? */
+ return -EIO;
+
+ return 0;
}
#ifdef CONFIG_EXT4_DEBUG
@@ -122,6 +188,7 @@ static int ext4_snapshot_read_through(struct inode *inode, sector_t iblock,
map.m_pblk = 0;
map.m_len = bh_result->b_size >> inode->i_blkbits;
+get_block:
prev_snapshot = NULL;
/* request snapshot file read access */
err = ext4_snapshot_get_block_access(inode, &prev_snapshot);
@@ -134,6 +201,11 @@ static int ext4_snapshot_read_through(struct inode *inode, sector_t iblock,
prev_snapshot ? prev_snapshot->i_generation : 0);
if (err < 0)
return err;
+ if (!err && prev_snapshot) {
+ /* hole in snapshot - check again with prev snapshot */
+ inode = prev_snapshot;
+ goto get_block;
+ }
if (!err)
/* hole in active snapshot - read though to block device */
return 0;
--
1.7.4.1
next prev parent reply other threads:[~2011-06-07 15:10 UTC|newest]
Thread overview: 73+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-07 15:07 [PATCH v1 00/30] Ext4 snapshots amir73il
2011-06-07 15:07 ` [PATCH v1 01/36] ext4: EXT4 snapshots (Experimental) amir73il
2011-06-07 15:07 ` [PATCH v1 02/36] ext4: snapshot debugging support amir73il
2011-06-07 15:07 ` [PATCH v1 03/36] ext4: snapshot hooks - inside JBD hooks amir73il
2011-06-07 15:07 ` [PATCH v1 04/36] ext4: snapshot hooks - block bitmap access amir73il
2011-06-07 15:07 ` [PATCH v1 05/36] ext4: snapshot hooks - delete blocks amir73il
2011-06-07 15:07 ` [PATCH v1 06/36] ext4: snapshot hooks - move data blocks amir73il
2011-06-07 15:07 ` [PATCH v1 07/36] ext4: snapshot hooks - direct I/O amir73il
2011-06-07 15:07 ` [PATCH v1 08/36] ext4: snapshot hooks - move extent file data blocks amir73il
2011-06-07 15:07 ` [PATCH v1 09/36] ext4: snapshot file amir73il
2011-06-07 15:07 ` [PATCH v1 10/36] ext4: snapshot file - read through to block device amir73il
2011-06-07 15:07 ` [PATCH v1 11/36] ext4: snapshot file - permissions amir73il
2011-06-07 15:07 ` [PATCH v1 12/36] ext4: snapshot file - store on disk amir73il
2011-06-07 15:07 ` [PATCH v1 13/36] ext4: snapshot file - increase maximum file size limit to 16TB amir73il
2011-06-07 15:07 ` [PATCH v1 14/36] ext4: snapshot block operations amir73il
2011-06-07 15:07 ` [PATCH v1 15/36] ext4: snapshot block operation - copy blocks to snapshot amir73il
2011-06-07 15:07 ` [PATCH v1 16/36] ext4: snapshot block operation - move " amir73il
2011-06-07 15:07 ` [PATCH v1 17/36] ext4: snapshot block operation - copy block bitmap " amir73il
2011-06-07 15:07 ` [PATCH v1 18/36] ext4: snapshot control amir73il
2011-06-07 15:07 ` [PATCH v1 19/36] ext4: snapshot control - init new snapshot amir73il
2011-06-07 15:07 ` [PATCH v1 20/36] ext4: snapshot control - fix " amir73il
2011-06-07 15:07 ` [PATCH v1 21/36] ext4: snapshot control - reserve disk space for snapshot amir73il
2011-06-07 15:07 ` [PATCH v1 22/36] ext4: snapshot journaled - increase transaction credits amir73il
2011-06-07 15:07 ` [PATCH v1 23/36] ext4: snapshot journaled - implement journal_release_buffer() amir73il
2011-06-07 15:07 ` [PATCH v1 24/36] ext4: snapshot journaled - bypass to save credits amir73il
2011-06-07 15:07 ` [PATCH v1 25/36] ext4: snapshot journaled - cache last COW tid in journal_head amir73il
2011-06-07 15:07 ` [PATCH v1 26/36] ext4: snapshot journaled - trace COW/buffer credits amir73il
2011-06-07 15:07 ` [PATCH v1 27/36] ext4: snapshot list support amir73il
2011-06-07 15:07 ` amir73il [this message]
2011-06-07 15:07 ` [PATCH v1 29/36] ext4: snapshot race conditions - concurrent COW bitmap operations amir73il
2011-06-07 15:07 ` [PATCH v1 30/36] ext4: snapshot race conditions - concurrent COW operations amir73il
2011-06-07 15:07 ` [PATCH v1 31/36] ext4: snapshot race conditions - tracked reads amir73il
2011-06-07 15:07 ` [PATCH v1 32/36] ext4: snapshot exclude - the exclude bitmap amir73il
2011-06-07 15:08 ` [PATCH v1 33/36] ext4: snapshot cleanup amir73il
2011-06-07 15:08 ` [PATCH v1 34/36] ext4: snapshot cleanup - shrink deleted snapshots amir73il
2011-06-07 15:08 ` [PATCH v1 35/36] ext4: snapshot cleanup - merge shrunk snapshots amir73il
2011-06-07 15:08 ` [PATCH v1 36/36] ext4: snapshot rocompat - enable rw mount amir73il
2011-06-07 15:56 ` [PATCH v1 00/30] Ext4 snapshots Lukas Czerner
2011-06-07 16:31 ` Amir G.
2011-06-08 10:09 ` Lukas Czerner
2011-06-08 14:04 ` Amir G.
2011-06-08 14:41 ` Eric Sandeen
2011-06-08 15:01 ` Amir G.
2011-06-08 15:22 ` Eric Sandeen
2011-06-08 15:33 ` Amir G.
2011-06-08 15:38 ` Lukas Czerner
2011-06-08 15:59 ` Amir G.
2011-06-08 16:19 ` Mike Snitzer
2011-06-09 1:59 ` Yongqiang Yang
2011-06-09 3:18 ` Amir G.
2011-06-09 3:51 ` Yongqiang Yang
2011-06-09 6:50 ` Lukas Czerner
2011-06-09 7:57 ` Amir G.
2011-06-09 8:13 ` david
2011-06-09 10:06 ` Amir G.
2011-06-09 10:17 ` Lukas Czerner
2011-06-09 8:46 ` Lukas Czerner
2011-06-09 10:54 ` Amir G.
2011-06-09 12:59 ` Lukas Czerner
2011-06-10 7:06 ` Amir G.
2011-06-10 9:00 ` Lukas Czerner
2011-06-10 12:02 ` Amir G.
2011-06-13 9:56 ` Amir G.
2011-06-13 10:54 ` Lukas Czerner
2011-06-13 12:56 ` Amir G.
2011-06-13 13:11 ` Lukas Czerner
2011-06-13 13:26 ` Amir G.
2011-06-13 13:50 ` Joe Thornber
2011-06-10 22:51 ` Valdis.Kletnieks
2011-06-11 1:09 ` Amir G.
2011-06-21 11:06 ` Amir G.
2011-06-21 15:45 ` Andreas Dilger
2011-06-22 6:38 ` Amir G.
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1307459283-22130-29-git-send-email-amir73il@users.sourceforge.net \
--to=amir73il@users.sourceforge.net \
--cc=amir73il@users.sf.net \
--cc=lczerner@redhat.com \
--cc=linux-ext4@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=xiaoqiangnk@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).