Commit 8b614cb8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '5.6-rc4-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Five small cifs/smb3 fixes, two for stable (one for a reconnect
  problem and the other fixes a use case when renaming an open file)"

* tag '5.6-rc4-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Use #define in cifs_dbg
  cifs: fix rename() by ensuring source handle opened with DELETE bit
  cifs: add missing mount option to /proc/mounts
  cifs: fix potential mismatch of UNC paths
  cifs: don't leak -EAGAIN for stat() during reconnect
parents 2873dc25 fb4b5f13
...@@ -324,6 +324,8 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt) ...@@ -324,6 +324,8 @@ static struct vfsmount *cifs_dfs_do_automount(struct dentry *mntpt)
if (full_path == NULL) if (full_path == NULL)
goto cdda_exit; goto cdda_exit;
convert_delimiter(full_path, '\\');
cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path); cifs_dbg(FYI, "%s: full_path: %s\n", __func__, full_path);
if (!cifs_sb_master_tlink(cifs_sb)) { if (!cifs_sb_master_tlink(cifs_sb)) {
......
...@@ -530,6 +530,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root) ...@@ -530,6 +530,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
if (tcon->seal) if (tcon->seal)
seq_puts(s, ",seal"); seq_puts(s, ",seal");
else if (tcon->ses->server->ignore_signature)
seq_puts(s, ",signloosely");
if (tcon->nocase) if (tcon->nocase)
seq_puts(s, ",nocase"); seq_puts(s, ",nocase");
if (tcon->local_lease) if (tcon->local_lease)
......
...@@ -1281,6 +1281,7 @@ struct cifs_fid { ...@@ -1281,6 +1281,7 @@ struct cifs_fid {
__u64 volatile_fid; /* volatile file id for smb2 */ __u64 volatile_fid; /* volatile file id for smb2 */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
__u8 create_guid[16]; __u8 create_guid[16];
__u32 access;
struct cifs_pending_open *pending_open; struct cifs_pending_open *pending_open;
unsigned int epoch; unsigned int epoch;
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
...@@ -1741,6 +1742,12 @@ static inline bool is_retryable_error(int error) ...@@ -1741,6 +1742,12 @@ static inline bool is_retryable_error(int error)
return false; return false;
} }
/* cifs_get_writable_file() flags */
#define FIND_WR_ANY 0
#define FIND_WR_FSUID_ONLY 1
#define FIND_WR_WITH_DELETE 2
#define MID_FREE 0 #define MID_FREE 0
#define MID_REQUEST_ALLOCATED 1 #define MID_REQUEST_ALLOCATED 1
#define MID_REQUEST_SUBMITTED 2 #define MID_REQUEST_SUBMITTED 2
......
...@@ -134,11 +134,12 @@ extern bool backup_cred(struct cifs_sb_info *); ...@@ -134,11 +134,12 @@ extern bool backup_cred(struct cifs_sb_info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written); unsigned int bytes_written);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, int);
extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
bool fsuid_only, int flags,
struct cifsFileInfo **ret_file); struct cifsFileInfo **ret_file);
extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
int flags,
struct cifsFileInfo **ret_file); struct cifsFileInfo **ret_file);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name, extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
......
...@@ -1492,6 +1492,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock, ...@@ -1492,6 +1492,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_parms *oparms, int *oplock,
*oplock = rsp->OplockLevel; *oplock = rsp->OplockLevel;
/* cifs fid stays in le */ /* cifs fid stays in le */
oparms->fid->netfid = rsp->Fid; oparms->fid->netfid = rsp->Fid;
oparms->fid->access = desired_access;
/* Let caller know file was created so we can set the mode. */ /* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */ /* Do we care about the CreateAction in any other cases? */
...@@ -2115,7 +2116,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) ...@@ -2115,7 +2116,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
wdata2->tailsz = tailsz; wdata2->tailsz = tailsz;
wdata2->bytes = cur_len; wdata2->bytes = cur_len;
rc = cifs_get_writable_file(CIFS_I(inode), false, rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY,
&wdata2->cfile); &wdata2->cfile);
if (!wdata2->cfile) { if (!wdata2->cfile) {
cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n", cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n",
......
...@@ -1958,7 +1958,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1958,7 +1958,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
/* Return -EBADF if no handle is found and general rc otherwise */ /* Return -EBADF if no handle is found and general rc otherwise */
int int
cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
struct cifsFileInfo **ret_file) struct cifsFileInfo **ret_file)
{ {
struct cifsFileInfo *open_file, *inv_file = NULL; struct cifsFileInfo *open_file, *inv_file = NULL;
...@@ -1966,7 +1966,8 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1966,7 +1966,8 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
bool any_available = false; bool any_available = false;
int rc = -EBADF; int rc = -EBADF;
unsigned int refind = 0; unsigned int refind = 0;
bool fsuid_only = flags & FIND_WR_FSUID_ONLY;
bool with_delete = flags & FIND_WR_WITH_DELETE;
*ret_file = NULL; *ret_file = NULL;
/* /*
...@@ -1998,6 +1999,8 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1998,6 +1999,8 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
continue; continue;
if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) if (fsuid_only && !uid_eq(open_file->uid, current_fsuid()))
continue; continue;
if (with_delete && !(open_file->fid.access & DELETE))
continue;
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
if (!open_file->invalidHandle) { if (!open_file->invalidHandle) {
/* found a good writable file */ /* found a good writable file */
...@@ -2045,12 +2048,12 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -2045,12 +2048,12 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
} }
struct cifsFileInfo * struct cifsFileInfo *
find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) find_writable_file(struct cifsInodeInfo *cifs_inode, int flags)
{ {
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
int rc; int rc;
rc = cifs_get_writable_file(cifs_inode, fsuid_only, &cfile); rc = cifs_get_writable_file(cifs_inode, flags, &cfile);
if (rc) if (rc)
cifs_dbg(FYI, "couldn't find writable handle rc=%d", rc); cifs_dbg(FYI, "couldn't find writable handle rc=%d", rc);
...@@ -2059,6 +2062,7 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) ...@@ -2059,6 +2062,7 @@ find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only)
int int
cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
int flags,
struct cifsFileInfo **ret_file) struct cifsFileInfo **ret_file)
{ {
struct list_head *tmp; struct list_head *tmp;
...@@ -2085,7 +2089,7 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name, ...@@ -2085,7 +2089,7 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
kfree(full_path); kfree(full_path);
cinode = CIFS_I(d_inode(cfile->dentry)); cinode = CIFS_I(d_inode(cfile->dentry));
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
return cifs_get_writable_file(cinode, 0, ret_file); return cifs_get_writable_file(cinode, flags, ret_file);
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&tcon->open_file_lock);
...@@ -2162,7 +2166,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) ...@@ -2162,7 +2166,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
if (mapping->host->i_size - offset < (loff_t)to) if (mapping->host->i_size - offset < (loff_t)to)
to = (unsigned)(mapping->host->i_size - offset); to = (unsigned)(mapping->host->i_size - offset);
rc = cifs_get_writable_file(CIFS_I(mapping->host), false, &open_file); rc = cifs_get_writable_file(CIFS_I(mapping->host), FIND_WR_ANY,
&open_file);
if (!rc) { if (!rc) {
bytes_written = cifs_write(open_file, open_file->pid, bytes_written = cifs_write(open_file, open_file->pid,
write_data, to - from, &offset); write_data, to - from, &offset);
...@@ -2355,7 +2360,7 @@ static int cifs_writepages(struct address_space *mapping, ...@@ -2355,7 +2360,7 @@ static int cifs_writepages(struct address_space *mapping,
if (cfile) if (cfile)
cifsFileInfo_put(cfile); cifsFileInfo_put(cfile);
rc = cifs_get_writable_file(CIFS_I(inode), false, &cfile); rc = cifs_get_writable_file(CIFS_I(inode), FIND_WR_ANY, &cfile);
/* in case of an error store it to return later */ /* in case of an error store it to return later */
if (rc) if (rc)
......
...@@ -653,8 +653,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, ...@@ -653,8 +653,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
*/ */
if ((fattr->cf_nlink < 1) && !tcon->unix_ext && if ((fattr->cf_nlink < 1) && !tcon->unix_ext &&
!info->DeletePending) { !info->DeletePending) {
cifs_dbg(1, "bogus file nlink value %u\n", cifs_dbg(VFS, "bogus file nlink value %u\n",
fattr->cf_nlink); fattr->cf_nlink);
fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK; fattr->cf_flags |= CIFS_FATTR_UNKNOWN_NLINK;
} }
} }
...@@ -2073,6 +2073,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) ...@@ -2073,6 +2073,7 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
char *full_path = NULL; char *full_path = NULL;
int count = 0;
if (inode == NULL) if (inode == NULL)
return -ENOENT; return -ENOENT;
...@@ -2094,15 +2095,18 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry) ...@@ -2094,15 +2095,18 @@ int cifs_revalidate_dentry_attr(struct dentry *dentry)
full_path, inode, inode->i_count.counter, full_path, inode, inode->i_count.counter,
dentry, cifs_get_time(dentry), jiffies); dentry, cifs_get_time(dentry), jiffies);
again:
if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext) if (cifs_sb_master_tcon(CIFS_SB(sb))->unix_ext)
rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid); rc = cifs_get_inode_info_unix(&inode, full_path, sb, xid);
else else
rc = cifs_get_inode_info(&inode, full_path, NULL, sb, rc = cifs_get_inode_info(&inode, full_path, NULL, sb,
xid, NULL); xid, NULL);
if (rc == -EAGAIN && count++ < 10)
goto again;
out: out:
kfree(full_path); kfree(full_path);
free_xid(xid); free_xid(xid);
return rc; return rc;
} }
...@@ -2278,7 +2282,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, ...@@ -2278,7 +2282,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
* writebehind data than the SMB timeout for the SetPathInfo * writebehind data than the SMB timeout for the SetPathInfo
* request would allow * request would allow
*/ */
open_file = find_writable_file(cifsInode, true); open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
if (open_file) { if (open_file) {
tcon = tlink_tcon(open_file->tlink); tcon = tlink_tcon(open_file->tlink);
server = tcon->ses->server; server = tcon->ses->server;
...@@ -2428,7 +2432,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) ...@@ -2428,7 +2432,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
args->ctime = NO_CHANGE_64; args->ctime = NO_CHANGE_64;
args->device = 0; args->device = 0;
open_file = find_writable_file(cifsInode, true); open_file = find_writable_file(cifsInode, FIND_WR_FSUID_ONLY);
if (open_file) { if (open_file) {
u16 nfid = open_file->fid.netfid; u16 nfid = open_file->fid.netfid;
u32 npid = open_file->pid; u32 npid = open_file->pid;
...@@ -2531,7 +2535,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) ...@@ -2531,7 +2535,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
rc = 0; rc = 0;
if (attrs->ia_valid & ATTR_MTIME) { if (attrs->ia_valid & ATTR_MTIME) {
rc = cifs_get_writable_file(cifsInode, false, &wfile); rc = cifs_get_writable_file(cifsInode, FIND_WR_ANY, &wfile);
if (!rc) { if (!rc) {
tcon = tlink_tcon(wfile->tlink); tcon = tlink_tcon(wfile->tlink);
rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid); rc = tcon->ses->server->ops->flush(xid, tcon, &wfile->fid);
......
...@@ -766,7 +766,7 @@ smb_set_file_info(struct inode *inode, const char *full_path, ...@@ -766,7 +766,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
/* if the file is already open for write, just use that fileid */ /* if the file is already open for write, just use that fileid */
open_file = find_writable_file(cinode, true); open_file = find_writable_file(cinode, FIND_WR_FSUID_ONLY);
if (open_file) { if (open_file) {
fid.netfid = open_file->fid.netfid; fid.netfid = open_file->fid.netfid;
netpid = open_file->pid; netpid = open_file->pid;
......
...@@ -521,7 +521,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name, ...@@ -521,7 +521,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
cifs_i = CIFS_I(inode); cifs_i = CIFS_I(inode);
dosattrs = cifs_i->cifsAttrs | ATTR_READONLY; dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
data.Attributes = cpu_to_le32(dosattrs); data.Attributes = cpu_to_le32(dosattrs);
cifs_get_writable_path(tcon, name, &cfile); cifs_get_writable_path(tcon, name, FIND_WR_ANY, &cfile);
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
FILE_WRITE_ATTRIBUTES, FILE_CREATE, FILE_WRITE_ATTRIBUTES, FILE_CREATE,
CREATE_NOT_FILE, ACL_NO_MODE, CREATE_NOT_FILE, ACL_NO_MODE,
...@@ -577,7 +577,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon, ...@@ -577,7 +577,7 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
{ {
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
cifs_get_writable_path(tcon, from_name, &cfile); cifs_get_writable_path(tcon, from_name, FIND_WR_WITH_DELETE, &cfile);
return smb2_set_path_attr(xid, tcon, from_name, to_name, return smb2_set_path_attr(xid, tcon, from_name, to_name,
cifs_sb, DELETE, SMB2_OP_RENAME, cfile); cifs_sb, DELETE, SMB2_OP_RENAME, cfile);
......
...@@ -1364,6 +1364,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) ...@@ -1364,6 +1364,7 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
cfile->fid.persistent_fid = fid->persistent_fid; cfile->fid.persistent_fid = fid->persistent_fid;
cfile->fid.volatile_fid = fid->volatile_fid; cfile->fid.volatile_fid = fid->volatile_fid;
cfile->fid.access = fid->access;
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
cfile->fid.mid = fid->mid; cfile->fid.mid = fid->mid;
#endif /* CIFS_DEBUG2 */ #endif /* CIFS_DEBUG2 */
...@@ -3327,7 +3328,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs ...@@ -3327,7 +3328,7 @@ static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offs
* some servers (Windows2016) will not reflect recent writes in * some servers (Windows2016) will not reflect recent writes in
* QUERY_ALLOCATED_RANGES until SMB2_flush is called. * QUERY_ALLOCATED_RANGES until SMB2_flush is called.
*/ */
wrcfile = find_writable_file(cifsi, false); wrcfile = find_writable_file(cifsi, FIND_WR_ANY);
if (wrcfile) { if (wrcfile) {
filemap_write_and_wait(inode->i_mapping); filemap_write_and_wait(inode->i_mapping);
smb2_flush_file(xid, tcon, &wrcfile->fid); smb2_flush_file(xid, tcon, &wrcfile->fid);
......
...@@ -2771,6 +2771,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, ...@@ -2771,6 +2771,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
atomic_inc(&tcon->num_remote_opens); atomic_inc(&tcon->num_remote_opens);
oparms->fid->persistent_fid = rsp->PersistentFileId; oparms->fid->persistent_fid = rsp->PersistentFileId;
oparms->fid->volatile_fid = rsp->VolatileFileId; oparms->fid->volatile_fid = rsp->VolatileFileId;
oparms->fid->access = oparms->desired_access;
#ifdef CONFIG_CIFS_DEBUG2 #ifdef CONFIG_CIFS_DEBUG2
oparms->fid->mid = le64_to_cpu(rsp->sync_hdr.MessageId); oparms->fid->mid = le64_to_cpu(rsp->sync_hdr.MessageId);
#endif /* CIFS_DEBUG2 */ #endif /* CIFS_DEBUG2 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment