Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 1355

kernel-2.6.18-238.el5.src.rpm

From: Brad Peters <bpeters@redhat.com>
Date: Fri, 12 Sep 2008 15:07:14 -0400
Subject: [gfs2] NFSv4 delegations fix for cluster systems
Message-id: 48CABDE2.3030304@redhat.com
O-Subject: Re: [PATCH RHEL 5.3] NFSv4 delegations fix for cluster systems - Revised patch
Bugzilla: 433256
RH-Acked-by: Peter Staubach <staubach@redhat.com>
RH-Acked-by: Steven Whitehouse <swhiteho@redhat.com>
RH-Acked-by: Steven Whitehouse <swhiteho@redhat.com>

RHBZ#:
------
https://bugzilla.redhat.com/show_bug.cgi?id=433256

Description:
------------
The backport of NFSv3 and NFSv4 cluster filesystem support from mainline
to RHEL5.2 did not correctly support NFS delegations (for NFSv4).  This
patch corrects this by exporting 'setlease' and using that function to
implement lease support.

RHEL Version Found:
------------------
5.2

kABI Status:
------------
No symbols were harmed.

Brew:
-----
Built on all platforms.
http://brewweb.devel.redhat.com/brew/taskinfo?taskID=1210293

Kernel binary rpm available at:
-----
http://people.redhat.com/bpeters/kernels/5.2/kernel-2.6.18-83.el5.83.el5.433256.ppc64.rpm

Upstream Status:
----------------
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=4698afe8e3a725576366f86560a8a8242b21b9f7

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=f9ffed26d6f3e6ac9988947242821579d615fda7

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=60446067ba7a8e890a91db3b4a7436fe0ebd2dee

Test Status:
------------
Tested that kernel is bootable and stable  3/14/08 <bpeters@redhat.com>

diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index dab323d..96228e1 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -139,9 +139,9 @@ void gfs2_set_iop(struct inode *inode)
 	if (S_ISREG(mode)) {
 		inode->i_op = &gfs2_file_iops;
 		if (sdp->sd_args.ar_localflocks)
-			inode->i_fop = &gfs2_file_fops_nolock;
+			inode->i_fop = (struct file_operations *)&gfs2_file_fops_nolock;
 		else
-			inode->i_fop = &gfs2_file_fops;
+			inode->i_fop = (struct file_operations *)&gfs2_file_fops;
 	} else if (S_ISDIR(mode)) {
 		inode->i_op = &gfs2_dir_iops;
 		if (sdp->sd_args.ar_localflocks)
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 7360278..98d96a5 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -507,6 +507,24 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
 }
 
 /**
+ * gfs2_setlease - acquire/release a file lease
+ * @file: the file pointer
+ * @arg: lease type
+ * @fl: file lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
+{
+	/*
+	 * We don't currently have a way to enforce a lease across the whole
+	 * cluster; until we do, disable leases (by just returning -EINVAL)
+	 */
+	return -EINVAL;
+}
+
+/**
  * gfs2_lock - acquire/release a posix lock on a file
  * @file: the file pointer
  * @cmd: either modify or retrieve lock state, possibly wait
@@ -633,24 +651,25 @@ static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
 		return do_flock(file, cmd, fl);
 }
 
-const struct file_operations gfs2_file_fops = {
-	.llseek		= gfs2_llseek,
-	.read		= generic_file_read,
-	.readv		= generic_file_readv,
-	.aio_read	= generic_file_aio_read,
-	.write		= generic_file_write,
-	.writev		= generic_file_writev,
-	.aio_write	= generic_file_aio_write,
-	.unlocked_ioctl	= gfs2_ioctl,
-	.mmap		= gfs2_mmap,
-	.open		= gfs2_open,
-	.release	= gfs2_close,
-	.fsync		= gfs2_fsync,
-	.lock		= gfs2_lock,
-	.sendfile	= generic_file_sendfile,
-	.flock		= gfs2_flock,
-	.splice_read	= generic_file_splice_read,
-	.splice_write	= generic_file_splice_write,
+const struct file_operations_ext gfs2_file_fops = {
+	.f_op_orig.llseek		= gfs2_llseek,
+	.f_op_orig.read		= generic_file_read,
+	.f_op_orig.readv		= generic_file_readv,
+	.f_op_orig.aio_read	= generic_file_aio_read,
+	.f_op_orig.write		= generic_file_write,
+	.f_op_orig.writev		= generic_file_writev,
+	.f_op_orig.aio_write	= generic_file_aio_write,
+	.f_op_orig.unlocked_ioctl	= gfs2_ioctl,
+	.f_op_orig.mmap		= gfs2_mmap,
+	.f_op_orig.open		= gfs2_open,
+	.f_op_orig.release	= gfs2_close,
+	.f_op_orig.fsync		= gfs2_fsync,
+	.f_op_orig.lock		= gfs2_lock,
+	.f_op_orig.sendfile	= generic_file_sendfile,
+	.f_op_orig.flock		= gfs2_flock,
+	.f_op_orig.splice_read	= generic_file_splice_read,
+	.f_op_orig.splice_write	= generic_file_splice_write,
+	.setlease = gfs2_setlease,
 };
 
 const struct file_operations gfs2_dir_fops = {
@@ -663,22 +682,25 @@ const struct file_operations gfs2_dir_fops = {
 	.flock		= gfs2_flock,
 };
 
-const struct file_operations gfs2_file_fops_nolock = {
-	.llseek		= gfs2_llseek,
-	.read		= generic_file_read,
-	.readv		= generic_file_readv,
-	.aio_read	= generic_file_aio_read,
-	.write		= generic_file_write,
-	.writev		= generic_file_writev,
-	.aio_write	= generic_file_aio_write,
-	.unlocked_ioctl	= gfs2_ioctl,
-	.mmap		= gfs2_mmap,
-	.open		= gfs2_open,
-	.release	= gfs2_close,
-	.fsync		= gfs2_fsync,
-	.sendfile	= generic_file_sendfile,
-	.splice_read	= generic_file_splice_read,
-	.splice_write	= generic_file_splice_write,
+const struct file_operations_ext gfs2_file_fops_nolock = {
+	.f_op_orig.llseek		= gfs2_llseek,
+	.f_op_orig.read		= generic_file_read,
+	.f_op_orig.readv		= generic_file_readv,
+	.f_op_orig.aio_read	= generic_file_aio_read,
+	.f_op_orig.write		= generic_file_write,
+	.f_op_orig.writev		= generic_file_writev,
+	.f_op_orig.aio_write	= generic_file_aio_write,
+	.f_op_orig.unlocked_ioctl	= gfs2_ioctl,
+	.f_op_orig.mmap		= gfs2_mmap,
+	.f_op_orig.open		= gfs2_open,
+	.f_op_orig.release	= gfs2_close,
+	.f_op_orig.fsync		= gfs2_fsync,
+	/* .f_op_orig.lock = NULL, */
+	.f_op_orig.sendfile	= generic_file_sendfile,
+	.f_op_orig.flock		= gfs2_flock,
+	.f_op_orig.splice_read	= generic_file_splice_read,
+	.f_op_orig.splice_write	= generic_file_splice_write,
+	/* .setlease = NULL, */
 };
 
 const struct file_operations gfs2_dir_fops_nolock = {
diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
index ff39b7a..554b857 100644
--- a/fs/gfs2/ops_file.h
+++ b/fs/gfs2/ops_file.h
@@ -18,9 +18,9 @@ extern int gfs2_internal_read(struct gfs2_inode *ip,
 			      struct file_ra_state *ra_state,
 			      char *buf, loff_t *pos, unsigned size);
 extern void gfs2_set_inode_flags(struct inode *inode);
-extern const struct file_operations gfs2_file_fops;
+extern const struct file_operations_ext gfs2_file_fops;
 extern const struct file_operations gfs2_dir_fops;
-extern const struct file_operations gfs2_file_fops_nolock;
+extern const struct file_operations_ext gfs2_file_fops_nolock;
 extern const struct file_operations gfs2_dir_fops_nolock;
 
 #endif /* __OPS_FILE_DOT_H__ */
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 7e97990..b6cff96 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -156,6 +156,8 @@ static void init_vfs(struct super_block *sb, unsigned noatime)
 
 	/* Don't let the VFS update atimes.  GFS2 handles this itself. */
 	sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
+	/* Indicate support for setlease fop */
+	sb->s_flags |= MS_HAS_SETLEASE;
 }
 
 /**
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 34e3ba2..4e4dee1 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -304,6 +304,8 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 
 	/* Don't let the VFS update atimes.  GFS2 handles this itself. */
 	*flags |= MS_NOATIME | MS_NODIRATIME;
+        /* Indicate support for setlease fop */
+        *flags |= MS_HAS_SETLEASE;
 
 	return error;
 }
diff --git a/fs/locks.c b/fs/locks.c
index cc00d13..6aa1018 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1367,7 +1367,7 @@ int fcntl_getlease(struct file *filp)
  *
  *	Called with kernel lock held.
  */
-static int __setlease(struct file *filp, long arg, struct file_lock **flp)
+int __setlease(struct file *filp, long arg, struct file_lock **flp)
 {
 	struct file_lock *fl, **before, **my_before = NULL, *lease;
 	struct dentry *dentry = filp->f_dentry;
@@ -1446,6 +1446,7 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
 out:
 	return error;
 }
+EXPORT_SYMBOL(__setlease);
 
  /**
  *	setlease        -       sets a lease on an open file
@@ -1454,13 +1455,31 @@ out:
  *	@lease: file_lock to use
  *
  *	Call this to establish a lease on the file.
- *	The fl_lmops fl_break function is required by break_lease
+ *	The (*lease)->fl_lmops->fl_break operation must be set; if not,
+ *	break_lease will oops!
+ *
+ *	This will call the filesystem's setlease file method, if
+ *	defined.  Note that there is no getlease method; instead, the
+ *	filesystem setlease method should call back to setlease() to
+ *	add a lease to the inode's lease list, where fcntl_getlease() can
+ *	find it.  Since fcntl_getlease() only reports whether the current
+ *	task holds a lease, a cluster filesystem need only do this for
+ *	leases held by processes on this node.
+ *
+ *	There is also no break_lease method; filesystems that
+ *	handle their own leases shoud break leases themselves from the
+ *	filesystem's open, create, and (on truncate) setattr methods.
+ *
+ *	Warning: the only current setlease methods exist only to disable
+ *	leases in certain cases.  More vfs changes may be required to
+ *	allow a full filesystem lease implementation.
  */
 
 int setlease(struct file *filp, long arg, struct file_lock **lease)
 {
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
+	struct file_operations_ext *fxops;
 	int error;
 
 	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
@@ -1471,8 +1490,12 @@ int setlease(struct file *filp, long arg, struct file_lock **lease)
 	if (error)
 		return error;
 
+	fxops = (struct file_operations_ext *)filp->f_op;
 	lock_kernel();
-	error = __setlease(filp, arg, lease);
+	if (IS_SETLEASE(inode) && fxops && fxops->setlease)
+		error = fxops->setlease(filp, arg, lease);
+	else
+		error = __setlease(filp, arg, lease);
 	unlock_kernel();
 
 	return error;
@@ -1500,14 +1523,6 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 	if (IS_NO_LEASES(inode))
 		return -EINVAL;
 
-	if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
-		return -EACCES;
-	if (!S_ISREG(inode->i_mode))
-		return -EINVAL;
-	error = security_file_lock(filp, arg);
-	if (error)
-		return error;
-
 	locks_init_lock(&fl);
 	error = lease_init(filp, arg, &fl);
 	if (error)
@@ -1515,7 +1530,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 
 	lock_kernel();
 
-	error = __setlease(filp, arg, &flp);
+	error = setlease(filp, arg, &flp);
 	if (error || arg == F_UNLCK)
 		goto out_unlock;
 
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1bac5e8..f6b7e12 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -121,6 +121,7 @@ extern int dir_notify_enable;
 #define MS_SLAVE	(1<<19)	/* change to slave */
 #define MS_SHARED	(1<<20)	/* change to shared */
 #define MS_NO_LEASES	(1<<21)	/* fs does not support leases */
+#define MS_HAS_SETLEASE        (1<<22) /* fs supports setlease fop */
 #define MS_I_VERSION	(1<<23)	/* Update inode I_version field */
 #define MS_ACTIVE	(1<<30)
 #define MS_NOUSER	(1<<31)
@@ -185,6 +186,7 @@ extern int dir_notify_enable;
 #define IS_SWAPFILE(inode)	((inode)->i_flags & S_SWAPFILE)
 #define IS_PRIVATE(inode)	((inode)->i_flags & S_PRIVATE)
 #define IS_NO_LEASES(inode)	__IS_FLG(inode, MS_NO_LEASES)
+#define IS_SETLEASE(inode)	__IS_FLG(inode, MS_HAS_SETLEASE)
 
 /* the read-only stuff doesn't really belong here, but any other place is
    probably as bad and I don't want to create yet another include file. */
@@ -860,6 +862,7 @@ extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
 extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
 extern int __break_lease(struct inode *inode, unsigned int flags);
 extern void lease_get_mtime(struct inode *, struct timespec *time);
+extern int __setlease(struct file *, long, struct file_lock **);
 extern int setlease(struct file *, long, struct file_lock **);
 extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
@@ -1127,6 +1130,13 @@ struct file_operations {
 	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
 };
 
+struct file_operations_ext {
+	struct file_operations f_op_orig;
+
+	/* setlease if MS_HAS_SETLEASE is set */
+	int (*setlease)(struct file *, long, struct file_lock **);
+};
+
 struct inode_operations {
 	int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
 	struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);