All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavel Shilovsky <piastry@etersoft.ru>
To: linux-kernel@vger.kernel.org
Cc: linux-fsdevel@vger.kernel.org, linux-cifs@vger.kernel.org,
	linux-nfs@vger.kernel.org, wine-devel@winehq.org
Subject: [PATCH v2 3/8] vfs: Add O_DENYREAD/WRITE flags support for open syscall
Date: Thu, 17 Jan 2013 20:52:59 +0400	[thread overview]
Message-ID: <1358441584-8783-3-git-send-email-piastry@etersoft.ru> (raw)
In-Reply-To: <1358441584-8783-1-git-send-email-piastry@etersoft.ru>

If O_DENYMAND flag is specified, O_DENYREAD/WRITE/MAND flags are
translated to flock's flags:

!O_DENYREAD  -> LOCK_READ
!O_DENYWRITE -> LOCK_WRITE
O_DENYMAND   -> LOCK_MAND

and set through flock_lock_file on a file.

This change only affects opens that use O_DENYMAND flag - all other
native Linux opens don't care about these flags. It allow us to
enable this feature for applications that need it (e.g. NFS and
Samba servers that export the same directory for Windows clients,
or Wine applications that access the same files simultaneously).

Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
---
 fs/locks.c         | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/namei.c         |  10 ++++-
 include/linux/fs.h |   6 +++
 3 files changed, 118 insertions(+), 4 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 9edfec4..ebe9a30 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -605,12 +605,86 @@ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *s
 	return (locks_conflict(caller_fl, sys_fl));
 }
 
-/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
+static unsigned int
+deny_flags_to_cmd(unsigned int flags)
+{
+	unsigned int cmd = LOCK_MAND;
+
+	if (!(flags & O_DENYREAD))
+		cmd |= LOCK_READ;
+	if (!(flags & O_DENYWRITE))
+		cmd |= LOCK_WRITE;
+
+	return cmd;
+}
+
+/*
+ * locks_mand_conflict - Determine if there's a share reservation conflict
+ * @caller_fl: lock we're attempting to acquire
+ * @sys_fl: lock already present on system that we're checking against
+ *
+ * Check to see if there's a share_reservation conflict. LOCK_READ/LOCK_WRITE
+ * tell us whether the reservation allows other readers and writers.
+ *
+ * We only check against other LOCK_MAND locks, so applications that want to
+ * use share mode locking will only conflict against one another. "normal"
+ * applications that open files won't be affected by and won't themselves
+ * affect the share reservations.
+ */
+static int
+locks_mand_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+{
+	unsigned char caller_type = caller_fl->fl_type;
+	unsigned char sys_type = sys_fl->fl_type;
+	fmode_t caller_fmode = caller_fl->fl_file->f_mode;
+	fmode_t sys_fmode = sys_fl->fl_file->f_mode;
+
+	/* they can only conflict if they're both LOCK_MAND */
+	if (!(caller_type & LOCK_MAND) || !(sys_type & LOCK_MAND))
+		return 0;
+
+	if (!(caller_type & LOCK_READ) && (sys_fmode & FMODE_READ))
+		return 1;
+	if (!(caller_type & LOCK_WRITE) && (sys_fmode & FMODE_WRITE))
+		return 1;
+	if (!(sys_type & LOCK_READ) && (caller_fmode & FMODE_READ))
+		return 1;
+	if (!(sys_type & LOCK_WRITE) && (caller_fmode & FMODE_WRITE))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Determine if lock sys_fl blocks lock caller_fl. O_DENY* flags specific
+ * checking before calling the locks_conflict().
+ */
+static int
+deny_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+{
+	/*
+	 * FLOCK locks referring to the same filp do not conflict with
+	 * each other.
+	 */
+	if (!IS_FLOCK(sys_fl))
+		return 0;
+	if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND))
+		return locks_mand_conflict(caller_fl, sys_fl);
+	if (caller_fl->fl_file == sys_fl->fl_file)
+		return 0;
+
+	return locks_conflict(caller_fl, sys_fl);
+}
+
+/*
+ * Determine if lock sys_fl blocks lock caller_fl. FLOCK specific
  * checking before calling the locks_conflict().
  */
-static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
+static int
+flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
 {
-	/* FLOCK locks referring to the same filp do not conflict with
+	/*
+	 * FLOCK locks referring to the same filp do not conflict with
 	 * each other.
 	 */
 	if (!IS_FLOCK(sys_fl) || (caller_fl->fl_file == sys_fl->fl_file))
@@ -789,6 +863,32 @@ out:
 	return error;
 }
 
+/*
+ * Determine if a file is allowed to be opened with specified access and deny
+ * modes. Lock the file and return 0 if checks passed, otherwise return a error
+ * code.
+ */
+int
+deny_lock_file(struct file *filp)
+{
+	struct file_lock *lock;
+	int error = 0;
+
+	if (!(filp->f_flags & O_DENYMAND))
+		return error;
+
+	error = flock_make_lock(filp, &lock, deny_flags_to_cmd(filp->f_flags));
+	if (error)
+		return error;
+
+	error = flock_lock_file(filp, lock, deny_locks_conflict);
+	if (error == -EAGAIN)
+		error = -ETXTBSY;
+
+	locks_free_lock(lock);
+	return error;
+}
+
 static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
 {
 	struct file_lock *fl;
diff --git a/fs/namei.c b/fs/namei.c
index 5f4cdf3..bf3bb34 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2569,9 +2569,14 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
 	 * here.
 	 */
 	error = may_open(&file->f_path, acc_mode, open_flag);
-	if (error)
+	if (error) {
 		fput(file);
+		goto out;
+	}
 
+	error = deny_lock_file(file);
+	if (error)
+		fput(file);
 out:
 	dput(dentry);
 	return error;
@@ -2908,6 +2913,9 @@ opened:
 		if (error)
 			goto exit_fput;
 	}
+	error = deny_lock_file(file);
+	if (error)
+		goto exit_fput;
 out:
 	if (got_write)
 		mnt_drop_write(nd->path.mnt);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 70a766ae..b8ed06e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1004,6 +1004,7 @@ extern int lease_modify(struct file_lock **, int);
 extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
 extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
 extern void locks_delete_block(struct file_lock *waiter);
+extern int deny_lock_file(struct file *);
 extern void lock_flocks(void);
 extern void unlock_flocks(void);
 #else /* !CONFIG_FILE_LOCKING */
@@ -1152,6 +1153,11 @@ static inline void locks_delete_block(struct file_lock *waiter)
 {
 }
 
+static inline int deny_lock_file(struct file *filp)
+{
+	return 0;
+}
+
 static inline void lock_flocks(void)
 {
 }
-- 
1.8.1.1

  parent reply	other threads:[~2013-01-17 16:52 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-01-17 16:52 [PATCH v2 1/8] locks: make flock_lock_file take is_conflict callback parm Pavel Shilovsky
2013-01-17 16:52 ` Pavel Shilovsky
2013-01-17 16:52 ` [PATCH v2 2/8] fcntl: Introduce new O_DENY* open flags Pavel Shilovsky
2013-01-17 16:52 ` Pavel Shilovsky [this message]
     [not found]   ` <1358441584-8783-3-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2013-01-30 22:16     ` [PATCH v2 3/8] vfs: Add O_DENYREAD/WRITE flags support for open syscall J. Bruce Fields
2013-01-30 22:16       ` J. Bruce Fields
     [not found]       ` <20130130221602.GC15584-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-05 11:45         ` Pavel Shilovsky
2013-02-05 11:45           ` Pavel Shilovsky
2013-02-05 14:35           ` J. Bruce Fields
2013-02-07  9:53             ` Pavel Shilovsky
     [not found]               ` <CAKywueS6oGNu9r_bypu32A89pOoiGb47kjXqw2ZcZQhZK+JV3g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-02-07 14:18                 ` J. Bruce Fields
2013-02-07 14:18                   ` J. Bruce Fields
     [not found]                   ` <20130207141832.GA3222-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-07 14:32                     ` Pavel Shilovsky
2013-02-07 14:32                       ` Pavel Shilovsky
     [not found]                       ` <CAKywueTmU_L5cwwJSoUY6753eHf_38VtHadZGt9tcLS59sqmOA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-02-07 14:41                         ` J. Bruce Fields
2013-02-07 14:41                           ` J. Bruce Fields
     [not found]                           ` <20130207144156.GB3222-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-07 16:00                             ` Pavel Shilovsky
2013-02-07 16:00                               ` Pavel Shilovsky
     [not found]                               ` <CAKywueShbPd9b+WmJwnfwPR_vzk_atBVRBZNTf-HpS7N2CK+AA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-02-07 16:19                                 ` J. Bruce Fields
2013-02-07 16:19                                   ` J. Bruce Fields
     [not found]                                   ` <20130207161948.GG3222-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-07 16:50                                     ` Pavel Shilovsky
2013-02-07 16:50                                       ` Pavel Shilovsky
2013-02-07 17:03                                       ` J. Bruce Fields
2013-01-17 16:53 ` [PATCH v2 4/8] CIFS: Add O_DENY* open flags support Pavel Shilovsky
     [not found]   ` <1358441584-8783-4-git-send-email-piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
2013-01-30 22:16     ` J. Bruce Fields
2013-01-30 22:16       ` J. Bruce Fields
     [not found]       ` <20130130221657.GD15584-uC3wQj2KruNg9hUCZPvPmw@public.gmane.org>
2013-02-05 11:54         ` Pavel Shilovsky
2013-02-05 11:54           ` Pavel Shilovsky
2013-01-17 16:53 ` [PATCH v2 5/8] CIFS: Use NT_CREATE_ANDX command for forcemand mounts Pavel Shilovsky
2013-01-17 16:53 ` [PATCH v2 6/8] CIFS: Translate SHARING_VIOLATION to -ETXTBSY error code for SMB2 Pavel Shilovsky
2013-01-17 16:53 ` [PATCH v2 7/8] NFSv4: Add O_DENY* open flags support Pavel Shilovsky
2013-01-17 16:53 ` [PATCH v2 8/8] NFSD: Pass share reservations flags to VFS Pavel Shilovsky

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=1358441584-8783-3-git-send-email-piastry@etersoft.ru \
    --to=piastry@etersoft.ru \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=wine-devel@winehq.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.