Commit c6ad7c3c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag '5.4-rc2-smb3' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs fixes from Steve French:
 "Eight small SMB3 fixes, four for stable, and important fix for the
  recent regression introduced by filesystem timestamp range patches"

* tag '5.4-rc2-smb3' of git://git.samba.org/sfrench/cifs-2.6:
  CIFS: Force reval dentry if LOOKUP_REVAL flag is set
  CIFS: Force revalidate inode when dentry is stale
  smb3: Fix regression in time handling
  smb3: remove noisy debug message and minor cleanup
  CIFS: Gracefully handle QueryInfo errors during open
  cifs: use cifsInodeInfo->open_file_lock while iterating to avoid a panic
  fs: cifs: mute -Wunused-const-variable message
  smb3: cleanup some recent endian errors spotted by updated sparse
parents c6f6ebd7 0b3d0ef9
...@@ -169,18 +169,26 @@ cifs_read_super(struct super_block *sb) ...@@ -169,18 +169,26 @@ cifs_read_super(struct super_block *sb)
else else
sb->s_maxbytes = MAX_NON_LFS; sb->s_maxbytes = MAX_NON_LFS;
/* BB FIXME fix time_gran to be larger for LANMAN sessions */ /* Some very old servers like DOS and OS/2 used 2 second granularity */
sb->s_time_gran = 100; if ((tcon->ses->server->vals->protocol_id == SMB10_PROT_ID) &&
((tcon->ses->capabilities &
if (tcon->unix_ext) { tcon->ses->server->vals->cap_nt_find) == 0) &&
ts = cifs_NTtimeToUnix(0); !tcon->unix_ext) {
sb->s_time_gran = 1000000000; /* 1 second is max allowed gran */
ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MIN), 0, 0);
sb->s_time_min = ts.tv_sec; sb->s_time_min = ts.tv_sec;
ts = cifs_NTtimeToUnix(cpu_to_le64(S64_MAX)); ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MAX),
cpu_to_le16(SMB_TIME_MAX), 0);
sb->s_time_max = ts.tv_sec; sb->s_time_max = ts.tv_sec;
} else { } else {
ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MIN), 0, 0); /*
* Almost every server, including all SMB2+, uses DCE TIME
* ie 100 nanosecond units, since 1601. See MS-DTYP and MS-FSCC
*/
sb->s_time_gran = 100;
ts = cifs_NTtimeToUnix(0);
sb->s_time_min = ts.tv_sec; sb->s_time_min = ts.tv_sec;
ts = cnvrtDosUnixTm(cpu_to_le16(SMB_DATE_MAX), cpu_to_le16(SMB_TIME_MAX), 0); ts = cifs_NTtimeToUnix(cpu_to_le64(S64_MAX));
sb->s_time_max = ts.tv_sec; sb->s_time_max = ts.tv_sec;
} }
......
...@@ -1210,7 +1210,7 @@ struct cifs_search_info { ...@@ -1210,7 +1210,7 @@ struct cifs_search_info {
bool smallBuf:1; /* so we know which buf_release function to call */ bool smallBuf:1; /* so we know which buf_release function to call */
}; };
#define ACL_NO_MODE -1 #define ACL_NO_MODE ((umode_t)(-1))
struct cifs_open_parms { struct cifs_open_parms {
struct cifs_tcon *tcon; struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
......
...@@ -4264,7 +4264,7 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb, ...@@ -4264,7 +4264,7 @@ static int mount_get_conns(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
server->ops->qfs_tcon(*xid, tcon); server->ops->qfs_tcon(*xid, tcon);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE) {
if (tcon->fsDevInfo.DeviceCharacteristics & if (tcon->fsDevInfo.DeviceCharacteristics &
FILE_READ_ONLY_DEVICE) cpu_to_le32(FILE_READ_ONLY_DEVICE))
cifs_dbg(VFS, "mounted to read only share\n"); cifs_dbg(VFS, "mounted to read only share\n");
else if ((cifs_sb->mnt_cifs_flags & else if ((cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_RW_CACHE) == 0) CIFS_MOUNT_RW_CACHE) == 0)
...@@ -4445,7 +4445,7 @@ static int setup_dfs_tgt_conn(const char *path, ...@@ -4445,7 +4445,7 @@ static int setup_dfs_tgt_conn(const char *path,
int rc; int rc;
struct dfs_info3_param ref = {0}; struct dfs_info3_param ref = {0};
char *mdata = NULL, *fake_devname = NULL; char *mdata = NULL, *fake_devname = NULL;
struct smb_vol fake_vol = {0}; struct smb_vol fake_vol = {NULL};
cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path); cifs_dbg(FYI, "%s: dfs path: %s\n", __func__, path);
......
...@@ -738,10 +738,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, ...@@ -738,10 +738,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
static int static int
cifs_d_revalidate(struct dentry *direntry, unsigned int flags) cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
{ {
struct inode *inode;
if (flags & LOOKUP_RCU) if (flags & LOOKUP_RCU)
return -ECHILD; return -ECHILD;
if (d_really_is_positive(direntry)) { if (d_really_is_positive(direntry)) {
inode = d_inode(direntry);
if ((flags & LOOKUP_REVAL) && !CIFS_CACHE_READ(CIFS_I(inode)))
CIFS_I(inode)->time = 0; /* force reval */
if (cifs_revalidate_dentry(direntry)) if (cifs_revalidate_dentry(direntry))
return 0; return 0;
else { else {
...@@ -752,7 +758,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags) ...@@ -752,7 +758,7 @@ cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
* attributes will have been updated by * attributes will have been updated by
* cifs_revalidate_dentry(). * cifs_revalidate_dentry().
*/ */
if (IS_AUTOMOUNT(d_inode(direntry)) && if (IS_AUTOMOUNT(inode) &&
!(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) { !(direntry->d_flags & DCACHE_NEED_AUTOMOUNT)) {
spin_lock(&direntry->d_lock); spin_lock(&direntry->d_lock);
direntry->d_flags |= DCACHE_NEED_AUTOMOUNT; direntry->d_flags |= DCACHE_NEED_AUTOMOUNT;
......
...@@ -253,6 +253,12 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, ...@@ -253,6 +253,12 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
xid, fid); xid, fid);
if (rc) {
server->ops->close(xid, tcon, fid);
if (rc == -ESTALE)
rc = -EOPENSTALE;
}
out: out:
kfree(buf); kfree(buf);
return rc; return rc;
...@@ -1840,13 +1846,12 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1840,13 +1846,12 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
{ {
struct cifsFileInfo *open_file = NULL; struct cifsFileInfo *open_file = NULL;
struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
/* only filter by fsuid on multiuser mounts */ /* only filter by fsuid on multiuser mounts */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
fsuid_only = false; fsuid_only = false;
spin_lock(&tcon->open_file_lock); spin_lock(&cifs_inode->open_file_lock);
/* we could simply get the first_list_entry since write-only entries /* we could simply get the first_list_entry since write-only entries
are always at the end of the list but since the first entry might are always at the end of the list but since the first entry might
have a close pending, we go through the whole list */ have a close pending, we go through the whole list */
...@@ -1858,7 +1863,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1858,7 +1863,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
/* found a good file */ /* found a good file */
/* lock it so it will not be closed on us */ /* lock it so it will not be closed on us */
cifsFileInfo_get(open_file); cifsFileInfo_get(open_file);
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
return open_file; return open_file;
} /* else might as well continue, and look for } /* else might as well continue, and look for
another, or simply have the caller reopen it another, or simply have the caller reopen it
...@@ -1866,7 +1871,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, ...@@ -1866,7 +1871,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
} else /* write only file */ } else /* write only file */
break; /* write only files are last so must be done */ break; /* write only files are last so must be done */
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
return NULL; return NULL;
} }
...@@ -1877,7 +1882,6 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1877,7 +1882,6 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
{ {
struct cifsFileInfo *open_file, *inv_file = NULL; struct cifsFileInfo *open_file, *inv_file = NULL;
struct cifs_sb_info *cifs_sb; struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
bool any_available = false; bool any_available = false;
int rc = -EBADF; int rc = -EBADF;
unsigned int refind = 0; unsigned int refind = 0;
...@@ -1897,16 +1901,15 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1897,16 +1901,15 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
} }
cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
tcon = cifs_sb_master_tcon(cifs_sb);
/* only filter by fsuid on multiuser mounts */ /* only filter by fsuid on multiuser mounts */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
fsuid_only = false; fsuid_only = false;
spin_lock(&tcon->open_file_lock); spin_lock(&cifs_inode->open_file_lock);
refind_writable: refind_writable:
if (refind > MAX_REOPEN_ATT) { if (refind > MAX_REOPEN_ATT) {
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
return rc; return rc;
} }
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
...@@ -1918,7 +1921,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1918,7 +1921,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
if (!open_file->invalidHandle) { if (!open_file->invalidHandle) {
/* found a good writable file */ /* found a good writable file */
cifsFileInfo_get(open_file); cifsFileInfo_get(open_file);
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
*ret_file = open_file; *ret_file = open_file;
return 0; return 0;
} else { } else {
...@@ -1938,7 +1941,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1938,7 +1941,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
cifsFileInfo_get(inv_file); cifsFileInfo_get(inv_file);
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
if (inv_file) { if (inv_file) {
rc = cifs_reopen_file(inv_file, false); rc = cifs_reopen_file(inv_file, false);
...@@ -1953,7 +1956,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, ...@@ -1953,7 +1956,7 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only,
cifsFileInfo_put(inv_file); cifsFileInfo_put(inv_file);
++refind; ++refind;
inv_file = NULL; inv_file = NULL;
spin_lock(&tcon->open_file_lock); spin_lock(&cifs_inode->open_file_lock);
goto refind_writable; goto refind_writable;
} }
...@@ -4461,17 +4464,15 @@ static int cifs_readpage(struct file *file, struct page *page) ...@@ -4461,17 +4464,15 @@ static int cifs_readpage(struct file *file, struct page *page)
static int is_inode_writable(struct cifsInodeInfo *cifs_inode) static int is_inode_writable(struct cifsInodeInfo *cifs_inode)
{ {
struct cifsFileInfo *open_file; struct cifsFileInfo *open_file;
struct cifs_tcon *tcon =
cifs_sb_master_tcon(CIFS_SB(cifs_inode->vfs_inode.i_sb));
spin_lock(&tcon->open_file_lock); spin_lock(&cifs_inode->open_file_lock);
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) {
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
return 1; return 1;
} }
} }
spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_inode->open_file_lock);
return 0; return 0;
} }
......
...@@ -414,6 +414,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -414,6 +414,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* if uniqueid is different, return error */ /* if uniqueid is different, return error */
if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) { CIFS_I(*pinode)->uniqueid != fattr.cf_uniqueid)) {
CIFS_I(*pinode)->time = 0; /* force reval */
rc = -ESTALE; rc = -ESTALE;
goto cgiiu_exit; goto cgiiu_exit;
} }
...@@ -421,6 +422,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, ...@@ -421,6 +422,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* if filetype is different, return error */ /* if filetype is different, return error */
if (unlikely(((*pinode)->i_mode & S_IFMT) != if (unlikely(((*pinode)->i_mode & S_IFMT) !=
(fattr.cf_mode & S_IFMT))) { (fattr.cf_mode & S_IFMT))) {
CIFS_I(*pinode)->time = 0; /* force reval */
rc = -ESTALE; rc = -ESTALE;
goto cgiiu_exit; goto cgiiu_exit;
} }
...@@ -933,6 +935,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -933,6 +935,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
/* if uniqueid is different, return error */ /* if uniqueid is different, return error */
if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM && if (unlikely(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM &&
CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) { CIFS_I(*inode)->uniqueid != fattr.cf_uniqueid)) {
CIFS_I(*inode)->time = 0; /* force reval */
rc = -ESTALE; rc = -ESTALE;
goto cgii_exit; goto cgii_exit;
} }
...@@ -940,6 +943,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, ...@@ -940,6 +943,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
/* if filetype is different, return error */ /* if filetype is different, return error */
if (unlikely(((*inode)->i_mode & S_IFMT) != if (unlikely(((*inode)->i_mode & S_IFMT) !=
(fattr.cf_mode & S_IFMT))) { (fattr.cf_mode & S_IFMT))) {
CIFS_I(*inode)->time = 0; /* force reval */
rc = -ESTALE; rc = -ESTALE;
goto cgii_exit; goto cgii_exit;
} }
......
...@@ -117,10 +117,6 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = { ...@@ -117,10 +117,6 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = {
{0, 0} {0, 0}
}; };
static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
{0, 0}
};
/* /*
* Convert a string containing text IPv4 or IPv6 address to binary form. * Convert a string containing text IPv4 or IPv6 address to binary form.
* *
......
...@@ -751,8 +751,8 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) ...@@ -751,8 +751,8 @@ add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
unsigned int num = *num_iovec; unsigned int num = *num_iovec;
iov[num].iov_base = create_posix_buf(mode); iov[num].iov_base = create_posix_buf(mode);
if (mode == -1) if (mode == ACL_NO_MODE)
cifs_dbg(VFS, "illegal mode\n"); /* BB REMOVEME */ cifs_dbg(FYI, "illegal mode\n");
if (iov[num].iov_base == NULL) if (iov[num].iov_base == NULL)
return -ENOMEM; return -ENOMEM;
iov[num].iov_len = sizeof(struct create_posix); iov[num].iov_len = sizeof(struct create_posix);
...@@ -2521,11 +2521,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock, ...@@ -2521,11 +2521,8 @@ SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
return rc; return rc;
} }
/* TODO: add handling for the mode on create */ if ((oparms->disposition == FILE_CREATE) &&
if (oparms->disposition == FILE_CREATE) (oparms->mode != ACL_NO_MODE)) {
cifs_dbg(VFS, "mode is 0x%x\n", oparms->mode); /* BB REMOVEME */
if ((oparms->disposition == FILE_CREATE) && (oparms->mode != -1)) {
if (n_iov > 2) { if (n_iov > 2) {
struct create_context *ccontext = struct create_context *ccontext =
(struct create_context *)iov[n_iov-1].iov_base; (struct create_context *)iov[n_iov-1].iov_base;
...@@ -3217,7 +3214,8 @@ SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst, ...@@ -3217,7 +3214,8 @@ SMB2_notify_init(const unsigned int xid, struct smb_rqst *rqst,
req->PersistentFileId = persistent_fid; req->PersistentFileId = persistent_fid;
req->VolatileFileId = volatile_fid; req->VolatileFileId = volatile_fid;
req->OutputBufferLength = SMB2_MAX_BUFFER_SIZE - MAX_SMB2_HDR_SIZE; req->OutputBufferLength =
cpu_to_le32(SMB2_MAX_BUFFER_SIZE - MAX_SMB2_HDR_SIZE);
req->CompletionFilter = cpu_to_le32(completion_filter); req->CompletionFilter = cpu_to_le32(completion_filter);
if (watch_tree) if (watch_tree)
req->Flags = cpu_to_le16(SMB2_WATCH_TREE); req->Flags = cpu_to_le16(SMB2_WATCH_TREE);
......
...@@ -150,6 +150,10 @@ extern int SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, ...@@ -150,6 +150,10 @@ extern int SMB2_ioctl_init(struct cifs_tcon *tcon, struct smb_rqst *rqst,
bool is_fsctl, char *in_data, u32 indatalen, bool is_fsctl, char *in_data, u32 indatalen,
__u32 max_response_size); __u32 max_response_size);
extern void SMB2_ioctl_free(struct smb_rqst *rqst); extern void SMB2_ioctl_free(struct smb_rqst *rqst);
extern int SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, bool watch_tree,
u32 completion_filter);
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id); u64 persistent_file_id, u64 volatile_file_id);
extern int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon, extern int SMB2_close_flags(const unsigned int xid, struct cifs_tcon *tcon,
......
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