From patchwork Thu Dec 5 04:21:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve French X-Patchwork-Id: 11274165 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 01BCA13A4 for ; Thu, 5 Dec 2019 04:21:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B5C442245C for ; Thu, 5 Dec 2019 04:21:16 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="TnTdXxR8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728449AbfLEEVQ (ORCPT ); Wed, 4 Dec 2019 23:21:16 -0500 Received: from mail-io1-f42.google.com ([209.85.166.42]:43453 "EHLO mail-io1-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728321AbfLEEVQ (ORCPT ); Wed, 4 Dec 2019 23:21:16 -0500 Received: by mail-io1-f42.google.com with SMTP id s2so2142201iog.10 for ; Wed, 04 Dec 2019 20:21:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=fgK975K2g7ukjKPJ+Q0K1KyjBNPwcv5UXT0k7SrNrx0=; b=TnTdXxR86zmlLhswBiA+K8oGQGKEs7nDRPK3roCRytCZ5o6a6SWhHXR2ajwPb+FSdZ 23eeZnVr/+HkSTRWVmf1ODlI1Zs3rp41dLi8zlDywTyG43zYBgJKu4HkSEDPR48CmlTV 82Uss7k8qP5vOt7O0DlTYzp6IcJccSga9c4V59F0MZo484dZJLUDI31PDFbksoFO0q0A kug+82f/0VwHCZ3RPZlIDxCw8/3un+ZPtWo//bio30mx1We2DiJvEaYY68TYpqtXGmzl TkuRg+OfEY0TpmuZu0w1EB4QnKHI/HaN+1X8LSfCxYgD6YL1Svb4/3cP7JVJaalL3CvE Wk2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=fgK975K2g7ukjKPJ+Q0K1KyjBNPwcv5UXT0k7SrNrx0=; b=rb4GTyOaY2pZpWbuxNRa4IQjfZubuBUZsd90x8Z6aWSOLEdmqZK7Kno26QHRJfCsGq 5cw5ZwMds/fKNJCTnGDLoh3LHi9i5VoZ2mcaQxNTEq0CbJaLEOfMCISpjt5ZXLMDGXIp fG2MLrBo5HQ0axIEvw/EKvYNacZugvNDplFFvNqKoYOU7sSjNN6JHyC41ujUYsybGbvL s9MN7MgKSW5nHkLCu3OTt8qCNrPhH9Dz6/qy3/iClHqHQhvS4ewGQYtiYyFb+V7kEp8h pNTXQpn8w1W5dXn6GzzdpElhFqU5O3TaQvCEd8FyLFvjjnYpP/XCj3JEhk1ZUhN9K9u6 uEdg== X-Gm-Message-State: APjAAAV8XvStX8laL1QEPQS0dcw38l4yFH+ny68W+kZKclJB+x/xBcRZ 1a1tNndKNzrxRNqsCzHmWrosOhrzDWGJkXR710RGUw== X-Google-Smtp-Source: APXvYqyUc2DuigrrmmWVa9cH5y4HxJeWZ3DAkr29JY55s3KzdmdWvkTswKnW/1LujorEFTJETYiLw4dbN/qI/G6KWCg= X-Received: by 2002:a02:a995:: with SMTP id q21mr6633037jam.27.1575519674349; Wed, 04 Dec 2019 20:21:14 -0800 (PST) MIME-Version: 1.0 From: Steve French Date: Wed, 4 Dec 2019 22:21:03 -0600 Message-ID: Subject: [PATCH][WIP] Add O_TMPFILE support for SMB3 To: CIFS Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org There are various testcases (xfstests) and apps that require support for O_TMPFILE and there is a similar concept in SMB3 on the wire ... but the Linux VFS calls create (for a tmpfile) and then open ... which is a problem (since tmpfiles would disappear after create/close in SMB if created with "DELETE_ON_CLOSE" ...) Here is a work in progress patch that gets part way to O_TMPFILE support over SMB3 ... any ideas how to get past the problem with the open/create of O_TMPFILE not being atomic (causing opencreate then close then open ...) See attached diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5d3e63aff253..3f7a18743ab3 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1045,6 +1045,7 @@ const struct inode_operations cifs_dir_inode_ops = { .setattr = cifs_setattr, .symlink = cifs_symlink, .mknod = cifs_mknod, + .tmpfile = smb3_tmpfile, .listxattr = cifs_listxattr, }; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index b59dc7478130..f3aa78bbf145 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -71,6 +71,7 @@ extern struct dentry *cifs_lookup(struct inode *, struct dentry *, extern int cifs_unlink(struct inode *dir, struct dentry *dentry); extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *); extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t); +extern int smb3_tmpfile(struct inode *, struct dentry *, umode_t); extern int cifs_mkdir(struct inode *, struct dentry *, umode_t); extern int cifs_rmdir(struct inode *, struct dentry *); extern int cifs_rename2(struct inode *, struct dentry *, struct inode *, diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 79d842e7240c..a4e12e655e61 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -374,6 +374,7 @@ #define CREATE_OPTIONS_MASK 0x007FFFFF #define CREATE_OPTION_READONLY 0x10000000 #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ +#define CREATE_OPTION_TMP 0x40000000 /* set hidden/temporary as attrs */ /* ImpersonationLevel flags */ #define SECURITY_ANONYMOUS 0 diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f3b79012ff29..6fd95c13cc2a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -220,12 +220,15 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon) } +/* minimum supported name length in old systems would be 8.3 names, 12 bytes */ +#define SHORT_NAME_LEN 12 /* 8 + 1 (for dot) + 3 */ + /* Inode operations in similar order to how they appear in Linux file fs.h */ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, struct tcon_link *tlink, unsigned oflags, umode_t mode, - __u32 *oplock, struct cifs_fid *fid) + __u32 *oplock, struct cifs_fid *fid, bool tmp) { int rc = -ENOENT; int create_options = CREATE_NOT_DIR; @@ -243,10 +246,21 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, if (tcon->ses->server->oplocks) *oplock = REQ_OPLOCK; - full_path = build_path_from_dentry(direntry); + if (tmp) + full_path = kmalloc(SHORT_NAME_LEN + 1 /* for trailing null */, + GFP_KERNEL); + else + full_path = build_path_from_dentry(direntry); if (!full_path) return -ENOMEM; + /* fill in 8.3 (maximum size on some old file systems) random name */ + if (tmp) { + scnprintf(full_path, SHORT_NAME_LEN, "%lu", jiffies); + full_path[SHORT_NAME_LEN] = 0; /* trailing null */ + full_path[8] = '.'; /* 8.3 names have . as eighth character */ + } + if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { @@ -321,6 +335,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, desired_access |= GENERIC_READ; /* is this too little? */ if (OPEN_FMODE(oflags) & FMODE_WRITE) desired_access |= GENERIC_WRITE; + if (tmp) + desired_access |= DELETE; disposition = FILE_OVERWRITE_IF; if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) @@ -448,6 +464,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, d_add(direntry, newinode); out: + cifs_dbg(VFS, "exiting cifs_do_create with rc %d\n",rc); /* BB REMOVEME */ kfree(buf); kfree(full_path); return rc; @@ -527,7 +544,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, cifs_add_pending_open(&fid, tlink, &open); rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, - &oplock, &fid); + &oplock, &fid, false); if (rc) { cifs_del_pending_open(&open); @@ -603,7 +620,47 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, server->ops->new_lease_key(&fid); rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, - &oplock, &fid); + &oplock, &fid, false); + if (!rc && server->ops->close) + server->ops->close(xid, tcon, &fid); + + + cifs_put_tlink(tlink); +out_free_xid: + free_xid(xid); + return rc; +} + +/* + * O_TMPFILE can be simulated over SMB3 using ATTR_TEMPORARY + */ +int smb3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + int rc = -EOPNOTSUPP; + unsigned int xid = get_xid(); + unsigned oflags = O_EXCL | O_CREAT | O_RDWR; + struct tcon_link *tlink; + struct cifs_tcon *tcon; + struct TCP_Server_Info *server; + struct cifs_fid fid; + __u32 oplock; + + cifs_dbg(FYI, "create tmpfile - dentry = 0x%p with mode 0x%x\n", + dentry, mode); + + tlink = cifs_sb_tlink(CIFS_SB(dir->i_sb)); + rc = PTR_ERR(tlink); + if (IS_ERR(tlink)) + goto out_free_xid; + + tcon = tlink_tcon(tlink); + server = tcon->ses->server; + + if (server->ops->new_lease_key) + server->ops->new_lease_key(&fid); + + rc = cifs_do_create(dir, dentry, xid, tlink, oflags, mode, + &oplock, &fid, true); if (!rc && server->ops->close) server->ops->close(xid, tcon, &fid); diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 187a5ce68806..8d191da41973 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2455,6 +2455,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock, file_attributes |= ATTR_READONLY; if (oparms->create_options & CREATE_OPTION_SPECIAL) file_attributes |= ATTR_SYSTEM; + if (oparms->create_options & CREATE_OPTION_TMP) + file_attributes |= ATTR_TEMPORARY | ATTR_HIDDEN; req->ImpersonationLevel = IL_IMPERSONATION; req->DesiredAccess = cpu_to_le32(oparms->desired_access);