public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] cowlinks v2
@ 2004-03-20  8:34 Jörn Engel
  2004-03-20  8:49 ` Andrew Morton
       [not found] ` <mit.lcs.mail.linux-kernel/20040320083411.GA25934@wohnheim.fh-wedel.de>
  0 siblings, 2 replies; 95+ messages in thread
From: Jörn Engel @ 2004-03-20  8:34 UTC (permalink / raw)
  To: linux-kernel; +Cc: Andrew Morton, viro, Sytse Wielinga

Hi!

Version 2 of my cowlink patch, tested and currently running on my
machine.

Al, I'd especially like your opinion on it.  Would you accept
something like this?

Changes since v1:
o moved break_cow_link() check to get_write_access()
o added inode locking when changing flags
o switched to mark_inode_dirty_sync()

TODO:
o Disallow fcntl() for filesystems without support
o Proper support for ext[23]
o Switch to mark_inode_dirty() without sync?
o Library support for
  o copyfile() (link and set cow-flag)
  o cow_open() (break link if open() fails)

Jörn

-- 
Premature optimization is the root of all evil.
-- Donald Knuth


 fs/ext2/inode.c       |    3 +-
 fs/ext3/inode.c       |    4 ++
 fs/fcntl.c            |   21 +++++++++++++++
 fs/namei.c            |   70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/fcntl.h |    3 ++
 include/linux/fs.h    |    3 ++
 6 files changed, 102 insertions(+), 2 deletions(-)

--- linux-2.6.4/include/linux/fcntl.h~cowlink	2004-03-19 17:38:48.000000000 +0100
+++ linux-2.6.4/include/linux/fcntl.h	2004-03-19 17:52:49.000000000 +0100
@@ -23,6 +23,9 @@
 #define DN_ATTRIB	0x00000020	/* File changed attibutes */
 #define DN_MULTISHOT	0x80000000	/* Don't remove notifier */
 
+#define F_SETCOW	(F_LINUX_SPECIFIC_BASE+3)
+#define F_GETCOW	(F_LINUX_SPECIFIC_BASE+4)
+
 #ifdef __KERNEL__
 
 #if BITS_PER_LONG == 32
--- linux-2.6.4/include/linux/fs.h~cowlink	2004-03-19 17:47:29.000000000 +0100
+++ linux-2.6.4/include/linux/fs.h	2004-03-19 17:52:49.000000000 +0100
@@ -137,6 +137,9 @@
 #define S_DEAD		32	/* removed, but still open directory */
 #define S_NOQUOTA	64	/* Inode is not counted to quota */
 #define S_DIRSYNC	128	/* Directory modifications are synchronous */
+#define S_COWLINK	256	/* Hard links have copy on write semantics.
+				 * This flag has no meaning for directories,
+				 * but is inherited to directory children */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
--- linux-2.6.4/fs/fcntl.c~cowlink	2004-03-19 17:47:15.000000000 +0100
+++ linux-2.6.4/fs/fcntl.c	2004-03-19 17:59:20.000000000 +0100
@@ -282,6 +282,20 @@
 
 EXPORT_SYMBOL(f_delown);
 
+static long fcntl_setcow(struct file *filp, unsigned long arg)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+
+	spin_lock(&inode->i_lock);
+	if (arg)
+		inode->i_flags |= S_COWLINK;
+	else
+		inode->i_flags &= ~S_COWLINK;
+	mark_inode_dirty_sync(inode);
+	spin_unlock(&inode->i_lock);
+	return 0;
+}
+
 static long do_fcntl(unsigned int fd, unsigned int cmd,
 		     unsigned long arg, struct file * filp)
 {
@@ -346,6 +360,13 @@
 		case F_NOTIFY:
 			err = fcntl_dirnotify(fd, filp, arg);
 			break;
+		case F_SETCOW:
+			err = fcntl_setcow(filp, arg);
+			break;
+		case F_GETCOW:
+			err = (filp->f_dentry->d_inode->i_flags & S_COWLINK) /
+				S_COWLINK;
+			break;
 		default:
 			break;
 	}
--- linux-2.6.4/fs/namei.c~cowlink	2004-03-19 17:47:19.000000000 +0100
+++ linux-2.6.4/fs/namei.c	2004-03-19 18:10:00.000000000 +0100
@@ -224,6 +224,33 @@
 }
 
 /*
+ * Files with the S_COWLINK flag set cannot be written to, if more
+ * than one hard link to them exists.  Ultimately, this function
+ * should copy the inode, assign the copy to the dentry and lower use
+ * count of the old inode - one day.
+ * For now, it is sufficient to return an error and let userspace
+ * deal with the messy part.  Not exactly the meaning of
+ * copy-on-write, but much better than writing to fifty files at once
+ * and noticing month later.
+ *
+ * Yes, this breaks the kernel interface and is simply wrong.  This
+ * is intended behaviour, so Linus will not merge the code before
+ * it is complete.  Or will he?
+ */
+static int break_cow_link(struct inode *inode)
+{
+	if (!(inode->i_flags & S_COWLINK))
+		return 0;
+	if (!S_ISREG(inode->i_mode))
+		return 0;
+	if (inode->i_nlink < 2)
+		return 0;
+	/* TODO: As soon as sendfile can do normal file copies, use that
+	 * and always return 0 */
+	return -EMLINK;
+}
+
+/*
  * get_write_access() gets write permission for a file.
  * put_write_access() releases this write permission.
  * This is used for regular files.
@@ -243,7 +270,14 @@
 
 int get_write_access(struct inode * inode)
 {
+	int error;
+
 	spin_lock(&inode->i_lock);
+	error = break_cow_link(inode);
+	if (error) {
+		spin_unlock(&inode->i_lock);
+		return error;
+	}
 	if (atomic_read(&inode->i_writecount) < 0) {
 		spin_unlock(&inode->i_lock);
 		return -ETXTBSY;
@@ -1148,6 +1182,10 @@
 	if (!error) {
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_create(dir, dentry, mode);
+		spin_lock(&inode->i_lock);
+		dentry->d_inode->i_flags |= dir->i_flags & S_COWLINK;
+		mark_inode_dirty_sync(inode);
+		spin_unlock(&inode->i_lock);
 	}
 	return error;
 }
@@ -1522,6 +1560,9 @@
 	if (!error) {
 		inode_dir_notify(dir, DN_CREATE);
 		security_inode_post_mkdir(dir,dentry, mode);
+		spin_lock(&inode->i_lock);
+		dentry->d_inode->i_flags |= dir->i_flags & S_COWLINK;
+		spin_unlock(&inode->i_lock);
 	}
 	return error;
 }
@@ -1820,6 +1861,13 @@
 		return -EXDEV;
 
 	/*
+	 * Cowlink attribute is inherited from directory, but here,
+	 * the inode already has one.  If they don't match, bail out.
+	 */
+	if ((dir->i_flags ^ old_dentry->d_inode->i_flags) & S_COWLINK)
+		return -EMLINK;
+
+	/*
 	 * A link to an append-only or immutable file cannot be created.
 	 */
 	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
@@ -1997,6 +2045,24 @@
 	return error;
 }
 
+static int cow_allow_rename(struct inode *old_dir, struct dentry *old_dentry,
+			    struct inode *new_dir)
+{
+	/* source and target share directory: allow */
+	if (old_dir == new_dir)
+		return 0;
+	/* source and target directory have identical cowlink flag: allow */
+	if (! ((old_dentry->d_inode->i_flags ^ new_dir->i_flags) & S_COWLINK))
+		return 0;
+	/* We could always fail here, but cowlink flag is only defined for
+	 * files and directories, so let's allow special files */
+	if (!S_ISREG(old_dentry->d_inode->i_mode))
+		return -EMLINK;
+	if (!S_ISDIR(old_dentry->d_inode->i_mode))
+		return -EMLINK;
+	return 0;
+}
+
 int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	       struct inode *new_dir, struct dentry *new_dentry)
 {
@@ -2020,6 +2086,10 @@
 	if (!old_dir->i_op || !old_dir->i_op->rename)
 		return -EPERM;
 
+	error = cow_allow_rename(old_dir, old_dentry, new_dir);
+	if (error)
+		return error;
+
 	DQUOT_INIT(old_dir);
 	DQUOT_INIT(new_dir);
 
--- linux-2.6.4/fs/ext2/inode.c~cowlink	2004-03-19 17:44:02.000000000 +0100
+++ linux-2.6.4/fs/ext2/inode.c	2004-03-19 17:52:49.000000000 +0100
@@ -1020,6 +1020,7 @@
 {
 	unsigned int flags = EXT2_I(inode)->i_flags;
 
+	inode->i_flags  = flags;
 	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
 	if (flags & EXT2_SYNC_FL)
 		inode->i_flags |= S_SYNC;
@@ -1191,7 +1192,7 @@
 
 	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
 	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
-	raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+	raw_inode->i_flags = cpu_to_le32(inode->i_flags);
 	raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
 	raw_inode->i_frag = ei->i_frag_no;
 	raw_inode->i_fsize = ei->i_frag_size;
--- linux-2.6.4/fs/ext3/inode.c~cowlink	2004-03-19 17:44:02.000000000 +0100
+++ linux-2.6.4/fs/ext3/inode.c	2004-03-19 17:52:49.000000000 +0100
@@ -2447,6 +2447,7 @@
 {
 	unsigned int flags = EXT3_I(inode)->i_flags;
 
+	inode->i_flags  = flags;
 	inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
 	if (flags & EXT3_SYNC_FL)
 		inode->i_flags |= S_SYNC;
@@ -2629,7 +2630,8 @@
 	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
 	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
 	raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
-	raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+	raw_inode->i_flags = cpu_to_le32((ei->i_flags & ~S_COWLINK) |
+					 (inode->i_flags & S_COWLINK));
 #ifdef EXT3_FRAGMENTS
 	raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
 	raw_inode->i_frag = ei->i_frag_no;

^ permalink raw reply	[flat|nested] 95+ messages in thread

end of thread, other threads:[~2004-04-05 18:03 UTC | newest]

Thread overview: 95+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-03-20  8:34 [PATCH] cowlinks v2 Jörn Engel
2004-03-20  8:49 ` Andrew Morton
2004-03-20 11:27   ` Jörn Engel
2004-03-20 19:28     ` Andrew Morton
2004-03-21 12:43       ` Jörn Engel
2004-03-21 18:53       ` Jörn Engel
     [not found] ` <mit.lcs.mail.linux-kernel/20040320083411.GA25934@wohnheim.fh-wedel.de>
2004-03-20 15:03   ` Patrick J. LoPresti
2004-03-20 15:23     ` Jörn Engel
2004-03-29 17:12       ` Pavel Machek
2004-03-29 21:05         ` Patrick J. LoPresti
2004-03-29 23:16           ` Pavel Machek
2004-03-31 14:34             ` Jamie Lokier
2004-03-31 14:45               ` Pavel Machek
2004-03-31 15:20                 ` Jamie Lokier
2004-04-02 11:44                 ` Tim Connors
2004-04-02 16:54             ` Jörn Engel
2004-04-02 18:01               ` Pavel Machek
2004-04-02 18:17                 ` Jörn Engel
2004-04-02 18:23                   ` Pavel Machek
2004-04-02 19:28                     ` Ross Biro
2004-04-02 21:35                       ` Pavel Machek
2004-04-05  8:12                       ` Jörn Engel
2004-04-05  8:19                         ` Pavel Machek
2004-04-05  8:45                           ` Jörn Engel
2004-04-02 20:09                     ` Jamie Lokier
2004-04-02 21:39                       ` Pavel Machek
2004-04-02 22:00                         ` Chris Friesen
2004-04-03  0:49                           ` Jamie Lokier
2004-04-03  8:23                             ` Pavel Machek
2004-04-03 13:15                               ` Jamie Lokier
2004-04-05  8:19                                 ` Jörn Engel
2004-04-05  8:22                                   ` Pavel Machek
2004-04-03  0:46                         ` Jamie Lokier
2004-04-03  1:04                         ` Jamie Lokier
2004-04-03  1:21                           ` Erik Andersen
2004-04-03  1:59                             ` Jamie Lokier
2004-04-03  3:55                               ` Ross Biro
2004-04-03  9:09                               ` Pavel Machek
2004-04-03 13:27                                 ` Jamie Lokier
2004-04-03 18:39                           ` Eric W. Biederman
2004-04-03 19:43                             ` Jamie Lokier
2004-04-03 20:30                               ` Eric W. Biederman
2004-04-03 21:59                                 ` Jamie Lokier
2004-04-04  8:15                                   ` Eric W. Biederman
2004-04-05  8:35                               ` Jörn Engel
2004-04-05  9:15                                 ` Eric W. Biederman
2004-04-05  9:18                                   ` Jörn Engel
2004-04-05 11:43                                   ` Pavel Machek
2004-04-05 12:17                                     ` Jamie Lokier
2004-04-05 12:39                                   ` Jamie Lokier
2004-04-05 12:41                                 ` Jamie Lokier
2004-04-05 18:03                                   ` Jörn Engel
2004-04-05 11:10                         ` jlnance
2004-04-05 11:46                           ` Pavel Machek
2004-04-05 12:35                           ` Jamie Lokier
2004-04-05  8:43                     ` Jörn Engel
2004-04-03 19:47               ` Eric W. Biederman
2004-04-05  8:54                 ` Jörn Engel
2004-04-05  9:07                   ` Eric W. Biederman
2004-03-20 16:48     ` Davide Libenzi
2004-03-21 12:57       ` Jörn Engel
2004-03-21 17:59         ` Davide Libenzi
2004-03-21 18:14           ` Jörn Engel
2004-03-21 20:26             ` Davide Libenzi
2004-03-21 20:35               ` Jörn Engel
2004-03-22  0:18             ` Eric W. Biederman
2004-03-22  0:25               ` Davide Libenzi
2004-03-22  5:07                 ` Eric W. Biederman
2004-03-22  5:11                   ` Davide Libenzi
2004-03-22 11:20                     ` Eric W. Biederman
2004-03-22 16:02                       ` Davide Libenzi
2004-03-25 17:49               ` Jamie Lokier
2004-03-25 18:06                 ` Eric W. Biederman
2004-03-25 19:43                   ` Jamie Lokier
2004-03-25 20:38                     ` Linus Torvalds
2004-03-25 22:16                       ` Eric W. Biederman
2004-04-01 14:53                         ` Jörn Engel
2004-04-02 11:54                         ` Tim Connors
2004-03-25 21:46                     ` Eric W. Biederman
2004-03-27 10:28                       ` Jamie Lokier
2004-03-27 21:00                         ` Eric W. Biederman
2004-03-27 21:42                           ` Jamie Lokier
2004-03-27 23:45                             ` Eric W. Biederman
2004-03-28  0:43                               ` Eric W. Biederman
2004-03-28 12:22                                 ` Jamie Lokier
2004-03-28 20:07                                   ` Eric W. Biederman
2004-03-28 23:55                                     ` Jamie Lokier
2004-03-29  1:31                                       ` Eric W. Biederman
2004-03-29 12:36                                         ` Jamie Lokier
2004-03-29 19:36                                           ` Eric W. Biederman
2004-03-29 23:05                                             ` Jamie Lokier
2004-03-29 23:58                                               ` Eric W. Biederman
2004-03-29  7:45                                       ` Denis Vlasenko
2004-03-29  9:28                             ` Pavel Machek
2004-03-29 12:40                               ` Jamie Lokier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox