From patchwork Mon Jul 1 16:49:54 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pavel Shilovsky X-Patchwork-Id: 2808911 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 1EF659F3C3 for ; Mon, 1 Jul 2013 16:44:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 134D9201BA for ; Mon, 1 Jul 2013 16:44:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0095A201C3 for ; Mon, 1 Jul 2013 16:44:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754599Ab3GAQnF (ORCPT ); Mon, 1 Jul 2013 12:43:05 -0400 Received: from mail-la0-f53.google.com ([209.85.215.53]:43647 "EHLO mail-la0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753353Ab3GAQnA (ORCPT ); Mon, 1 Jul 2013 12:43:00 -0400 Received: by mail-la0-f53.google.com with SMTP id fs12so4566262lab.26 for ; Mon, 01 Jul 2013 09:42:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=8NHe59G26qOb46oalLzqHLhuaenZDX46ot6X9HUF1wc=; b=gEpy3HL1e4TgJ0opYHuVaL6GDu4aGbC3GEHJkpyEBDnZluu36TpmSgBKfPGwjHTR4X ZrufyZKyr6Jia+CK4p73ZywC3Q0SRYicVVnKfHURZa1O3wjH3QIRVIyUrVhxxsokbt82 5EYciEZ7nLHamx0uDl3Q2m3eHUiVgbbSpiyyfz/ZMmj6zl5lsFXauDASeSD1onMNzY6y J6Yu0LBY/QFvWPe3fmr3aGq0Z2tp2YEd6v0AbtiZL3JRxkLmKtMLfclCoGgVXU0aGLvT IqKKdlW1STeRRpTbItRnMGXoCgwGUM62Rh1Ar2YgaGfL/MfiWK49CrLHwyhUWk1o06o/ dltQ== X-Received: by 10.152.19.194 with SMTP id h2mr12464508lae.26.1372696978144; Mon, 01 Jul 2013 09:42:58 -0700 (PDT) Received: from workstation.localdomain (PPPoE-78-29-83-145.san.ru. [78.29.83.145]) by mx.google.com with ESMTPSA id m1sm7595442lag.3.2013.07.01.09.42.56 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 01 Jul 2013 09:42:57 -0700 (PDT) From: Pavel Shilovsky To: linux-kernel@vger.kernel.org Cc: linux-cifs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, wine-devel@winehq.org Subject: [PATCH v7 2/7] VFS: Add O_DENYDELETE support for VFS Date: Mon, 1 Jul 2013 20:49:54 +0400 Message-Id: <1372697399-21361-3-git-send-email-piastry@etersoft.ru> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1372697399-21361-1-git-send-email-piastry@etersoft.ru> References: <1372697399-21361-1-git-send-email-piastry@etersoft.ru> Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Introduce new LOCK_DELETE flock flag that is suggested to be used internally only to map O_DENYDELETE open flag: !O_DENYDELETE -> LOCK_DELETE | LOCK_MAND. Signed-off-by: Pavel Shilovsky --- fs/locks.c | 55 +++++++++++++++++++++++++++++++++------- fs/namei.c | 3 +++ include/linux/fs.h | 6 +++++ include/uapi/asm-generic/fcntl.h | 1 + 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/fs/locks.c b/fs/locks.c index dbc5557..c2fa136 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -269,7 +269,7 @@ EXPORT_SYMBOL(locks_copy_lock); static inline int flock_translate_cmd(int cmd) { if (cmd & LOCK_MAND) - return cmd & (LOCK_MAND | LOCK_RW); + return cmd & (LOCK_MAND | LOCK_RW | LOCK_DELETE); switch (cmd) { case LOCK_SH: return F_RDLCK; @@ -614,6 +614,8 @@ deny_flags_to_cmd(unsigned int flags) cmd |= LOCK_READ; if (!(flags & O_DENYWRITE)) cmd |= LOCK_WRITE; + if (!(flags & O_DENYDELETE)) + cmd |= LOCK_DELETE; return cmd; } @@ -836,6 +838,33 @@ out: return error; } +int +sharelock_may_delete(struct dentry *dentry) +{ + struct file_lock **before; + int rc = 0; + + if (!IS_SHARELOCK(dentry->d_inode)) + return rc; + + lock_flocks(); + for_each_lock(dentry->d_inode, before) { + struct file_lock *fl = *before; + if (IS_POSIX(fl)) + break; + if (IS_LEASE(fl)) + continue; + if (!(fl->fl_type & LOCK_MAND)) + continue; + if (fl->fl_type & LOCK_DELETE) + continue; + rc = 1; + break; + } + unlock_flocks(); + return rc; +} + /* * Determine if a file is allowed to be opened with specified access and share * modes. Lock the file and return 0 if checks passed, otherwise return @@ -850,10 +879,6 @@ sharelock_lock_file(struct file *filp) if (!IS_SHARELOCK(filp->f_path.dentry->d_inode)) return error; - /* Disable O_DENYDELETE support for now */ - if (filp->f_flags & O_DENYDELETE) - return -EINVAL; - error = flock_make_lock(filp, &lock, deny_flags_to_cmd(filp->f_flags)); if (error) return error; @@ -1717,6 +1742,12 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd) if (!f.file) goto out; + /* LOCK_DELETE is defined to be translated from O_DENYDELETE only */ + if (cmd & LOCK_DELETE) { + error = -EINVAL; + goto out; + } + can_sleep = !(cmd & LOCK_NB); cmd &= ~LOCK_NB; unlock = (cmd == LOCK_UN); @@ -2261,10 +2292,16 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl, seq_printf(f, "UNKNOWN UNKNOWN "); } if (fl->fl_type & LOCK_MAND) { - seq_printf(f, "%s ", - (fl->fl_type & LOCK_READ) - ? (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " - : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); + if (fl->fl_type & LOCK_DELETE) + seq_printf(f, "%s ", + (fl->fl_type & LOCK_READ) ? + (fl->fl_type & LOCK_WRITE) ? "RWDEL" : "RDDEL" : + (fl->fl_type & LOCK_WRITE) ? "WRDEL" : "DEL "); + else + seq_printf(f, "%s ", + (fl->fl_type & LOCK_READ) ? + (fl->fl_type & LOCK_WRITE) ? "RW " : "READ " : + (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE "); } else { seq_printf(f, "%s ", (lease_breaking(fl)) diff --git a/fs/namei.c b/fs/namei.c index 7f6edb9..8aaffd4 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2220,6 +2220,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode) * 9. We can't remove a root or mountpoint. * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). + * 11. We can't do it if victim is locked by O_DENYDELETE sharelock. */ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) { @@ -2250,6 +2251,8 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir) return -ENOENT; if (victim->d_flags & DCACHE_NFSFS_RENAMED) return -EBUSY; + if (sharelock_may_delete(victim)) + return -ESHAREDENIED; return 0; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 774be38..3247fb4 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1006,6 +1006,7 @@ 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 sharelock_lock_file(struct file *); +extern int sharelock_may_delete(struct dentry *); extern void lock_flocks(void); extern void unlock_flocks(void); #else /* !CONFIG_FILE_LOCKING */ @@ -1159,6 +1160,11 @@ static inline int sharelock_lock_file(struct file *filp) return 0; } +static inline int sharelock_may_delete(struct dentry *dentry) +{ + return 0; +} + static inline void lock_flocks(void) { } diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h index 5ac0d49..a3e6349 100644 --- a/include/uapi/asm-generic/fcntl.h +++ b/include/uapi/asm-generic/fcntl.h @@ -167,6 +167,7 @@ struct f_owner_ex { blocking */ #define LOCK_UN 8 /* remove lock */ +#define LOCK_DELETE 16 /* which allows to delete a file */ #define LOCK_MAND 32 /* This is a mandatory flock ... */ #define LOCK_READ 64 /* which allows concurrent read operations */ #define LOCK_WRITE 128 /* which allows concurrent write operations */