Skip to content

Commit

Permalink
Merge tag '5.13-rc-smb3-part2' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
Pull cifs updates from Steve French:
 "Ten CIFS/SMB3 changes - including two marked for stable - including
  some important multichannel fixes, as well as support for handle
  leases (deferred close) and shutdown support:

   - some important multichannel fixes

   - support for handle leases (deferred close)

   - shutdown support (which is also helpful since it enables multiple
     xfstests)

   - enable negotiating stronger encryption by default (GCM256)

   - improve wireshark debugging by allowing more options for root to
     dump decryption keys

  SambaXP and the SMB3 Plugfest test event are going on now so I am
  expecting more patches over the next few days due to extra testing
  (including more multichannel fixes)"

* tag '5.13-rc-smb3-part2' of git://git.samba.org/sfrench/cifs-2.6:
  fs/cifs: Fix resource leak
  Cifs: Fix kernel oops caused by deferred close for files.
  cifs: fix regression when mounting shares with prefix paths
  cifs: use echo_interval even when connection not ready.
  cifs: detect dead connections only when echoes are enabled.
  smb3.1.1: allow dumping keys for multiuser mounts
  smb3.1.1: allow dumping GCM256 keys to improve debugging of encrypted shares
  cifs: add shutdown support
  cifs: Deferred close for files
  smb3.1.1: enable negotiating stronger encryption by default
  • Loading branch information
torvalds committed May 5, 2021
2 parents 16bb86b + bae4c0c commit 7c9e41e
Show file tree
Hide file tree
Showing 14 changed files with 447 additions and 33 deletions.
1 change: 1 addition & 0 deletions fs/cifs/cifs_fs_sb.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#define CIFS_MOUNT_MODE_FROM_SID 0x10000000 /* retrieve mode from special ACE */
#define CIFS_MOUNT_RO_CACHE 0x20000000 /* assumes share will not change */
#define CIFS_MOUNT_RW_CACHE 0x40000000 /* assumes only client accessing */
#define CIFS_MOUNT_SHUTDOWN 0x80000000

struct cifs_sb_info {
struct rb_root tlink_tree;
Expand Down
35 changes: 35 additions & 0 deletions fs/cifs/cifs_ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ struct smb_query_info {
/* char buffer[]; */
} __packed;

/*
* Dumping the commonly used 16 byte (e.g. CCM and GCM128) keys still supported
* for backlevel compatibility, but is not sufficient for dumping the less
* frequently used GCM256 (32 byte) keys (see the newer "CIFS_DUMP_FULL_KEY"
* ioctl for dumping decryption info for GCM256 mounts)
*/
struct smb3_key_debug_info {
__u64 Suid;
__u16 cipher_type;
Expand All @@ -65,6 +71,18 @@ struct smb3_key_debug_info {
__u8 smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
} __packed;

/*
* Dump full key (32 byte encrypt/decrypt keys instead of 16 bytes)
* is needed if GCM256 (stronger encryption) negotiated
*/
struct smb3_full_key_debug_info {
__u64 Suid;
__u16 cipher_type;
__u8 auth_key[16]; /* SMB2_NTLMV2_SESSKEY_SIZE */
__u8 smb3encryptionkey[32]; /* SMB3_ENC_DEC_KEY_SIZE */
__u8 smb3decryptionkey[32]; /* SMB3_ENC_DEC_KEY_SIZE */
} __packed;

struct smb3_notify {
__u32 completion_filter;
bool watch_tree;
Expand All @@ -78,3 +96,20 @@ struct smb3_notify {
#define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info)
#define CIFS_DUMP_KEY _IOWR(CIFS_IOCTL_MAGIC, 8, struct smb3_key_debug_info)
#define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify)
#define CIFS_DUMP_FULL_KEY _IOWR(CIFS_IOCTL_MAGIC, 10, struct smb3_full_key_debug_info)
#define CIFS_IOC_SHUTDOWN _IOR ('X', 125, __u32)

/*
* Flags for going down operation
*/
#define CIFS_GOING_FLAGS_DEFAULT 0x0 /* going down */
#define CIFS_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
#define CIFS_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */

static inline bool cifs_forced_shutdown(struct cifs_sb_info *sbi)
{
if (CIFS_MOUNT_SHUTDOWN & sbi->mnt_cifs_flags)
return true;
else
return false;
}
25 changes: 16 additions & 9 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ bool enable_oplocks = true;
bool linuxExtEnabled = true;
bool lookupCacheEnabled = true;
bool disable_legacy_dialects; /* false by default */
bool enable_gcm_256; /* false by default, change when more servers support it */
bool enable_gcm_256 = true;
bool require_gcm_256; /* false by default */
unsigned int global_secflags = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
Expand Down Expand Up @@ -133,6 +133,7 @@ struct workqueue_struct *cifsiod_wq;
struct workqueue_struct *decrypt_wq;
struct workqueue_struct *fileinfo_put_wq;
struct workqueue_struct *cifsoplockd_wq;
struct workqueue_struct *deferredclose_wq;
__u32 cifs_lock_secret;

/*
Expand Down Expand Up @@ -390,6 +391,8 @@ cifs_alloc_inode(struct super_block *sb)
/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; */
INIT_LIST_HEAD(&cifs_inode->openFileList);
INIT_LIST_HEAD(&cifs_inode->llist);
INIT_LIST_HEAD(&cifs_inode->deferred_closes);
spin_lock_init(&cifs_inode->deferred_lock);
return &cifs_inode->vfs_inode;
}

Expand Down Expand Up @@ -860,13 +863,7 @@ cifs_smb3_do_mount(struct file_system_type *fs_type,
goto out;
}

/* cifs_setup_volume_info->smb3_parse_devname() redups UNC & prepath */
kfree(cifs_sb->ctx->UNC);
cifs_sb->ctx->UNC = NULL;
kfree(cifs_sb->ctx->prepath);
cifs_sb->ctx->prepath = NULL;

rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, old_ctx->UNC);
rc = cifs_setup_volume_info(cifs_sb->ctx, NULL, NULL);
if (rc) {
root = ERR_PTR(rc);
goto out;
Expand Down Expand Up @@ -1637,9 +1634,16 @@ init_cifs(void)
goto out_destroy_fileinfo_put_wq;
}

deferredclose_wq = alloc_workqueue("deferredclose",
WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
if (!deferredclose_wq) {
rc = -ENOMEM;
goto out_destroy_cifsoplockd_wq;
}

rc = cifs_fscache_register();
if (rc)
goto out_destroy_cifsoplockd_wq;
goto out_destroy_deferredclose_wq;

rc = cifs_init_inodecache();
if (rc)
Expand Down Expand Up @@ -1707,6 +1711,8 @@ init_cifs(void)
cifs_destroy_inodecache();
out_unreg_fscache:
cifs_fscache_unregister();
out_destroy_deferredclose_wq:
destroy_workqueue(deferredclose_wq);
out_destroy_cifsoplockd_wq:
destroy_workqueue(cifsoplockd_wq);
out_destroy_fileinfo_put_wq:
Expand Down Expand Up @@ -1741,6 +1747,7 @@ exit_cifs(void)
cifs_destroy_mids();
cifs_destroy_inodecache();
cifs_fscache_unregister();
destroy_workqueue(deferredclose_wq);
destroy_workqueue(cifsoplockd_wq);
destroy_workqueue(decrypt_wq);
destroy_workqueue(fileinfo_put_wq);
Expand Down
17 changes: 17 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,14 @@ struct cifs_pending_open {
__u32 oplock;
};

struct cifs_deferred_close {
struct list_head dlist;
struct tcon_link *tlink;
__u16 netfid;
__u64 persistent_fid;
__u64 volatile_fid;
};

/*
* This info hangs off the cifsFileInfo structure, pointed to by llist.
* This is used to track byte stream locks on the file
Expand Down Expand Up @@ -1248,6 +1256,9 @@ struct cifsFileInfo {
struct cifs_search_info srch_inf;
struct work_struct oplock_break; /* work for oplock breaks */
struct work_struct put; /* work for the final part of _put */
struct delayed_work deferred;
bool oplock_break_received; /* Flag to indicate oplock break */
bool deferred_scheduled;
};

struct cifs_io_parms {
Expand Down Expand Up @@ -1392,6 +1403,7 @@ struct cifsInodeInfo {
#define CIFS_INO_DELETE_PENDING (3) /* delete pending on server */
#define CIFS_INO_INVALID_MAPPING (4) /* pagecache is invalid */
#define CIFS_INO_LOCK (5) /* lock bit for synchronization */
#define CIFS_INO_MODIFIED_ATTR (6) /* Indicate change in mtime/ctime */
unsigned long flags;
spinlock_t writers_lock;
unsigned int writers; /* Number of writers on this inode */
Expand All @@ -1404,6 +1416,8 @@ struct cifsInodeInfo {
struct fscache_cookie *fscache;
#endif
struct inode vfs_inode;
struct list_head deferred_closes; /* list of deferred closes */
spinlock_t deferred_lock; /* protection on deferred list */
};

static inline struct cifsInodeInfo *
Expand Down Expand Up @@ -1871,11 +1885,14 @@ extern bool disable_legacy_dialects; /* forbid vers=1.0 and vers=2.0 mounts */

void cifs_oplock_break(struct work_struct *work);
void cifs_queue_oplock_break(struct cifsFileInfo *cfile);
void smb2_deferred_work_close(struct work_struct *work);

extern const struct slow_work_ops cifs_oplock_break_ops;
extern struct workqueue_struct *cifsiod_wq;
extern struct workqueue_struct *decrypt_wq;
extern struct workqueue_struct *fileinfo_put_wq;
extern struct workqueue_struct *cifsoplockd_wq;
extern struct workqueue_struct *deferredclose_wq;
extern __u32 cifs_lock_secret;

extern mempool_t *cifs_mid_poolp;
Expand Down
13 changes: 13 additions & 0 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,19 @@ extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
struct tcon_link *tlink,
struct cifs_pending_open *open);
extern void cifs_del_pending_open(struct cifs_pending_open *open);

extern bool cifs_is_deferred_close(struct cifsFileInfo *cfile,
struct cifs_deferred_close **dclose);

extern void cifs_add_deferred_close(struct cifsFileInfo *cfile,
struct cifs_deferred_close *dclose);

extern void cifs_del_deferred_close(struct cifsFileInfo *cfile);

extern void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);

extern void cifs_close_all_deferred_files(struct cifs_tcon *cifs_tcon);

extern struct TCP_Server_Info *cifs_get_tcp_session(struct smb3_fs_context *ctx);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect);
Expand Down
37 changes: 20 additions & 17 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -392,16 +392,6 @@ cifs_echo_request(struct work_struct *work)
int rc;
struct TCP_Server_Info *server = container_of(work,
struct TCP_Server_Info, echo.work);
unsigned long echo_interval;

/*
* If we need to renegotiate, set echo interval to zero to
* immediately call echo service where we can renegotiate.
*/
if (server->tcpStatus == CifsNeedNegotiate)
echo_interval = 0;
else
echo_interval = server->echo_interval;

/*
* We cannot send an echo if it is disabled.
Expand All @@ -412,7 +402,7 @@ cifs_echo_request(struct work_struct *work)
server->tcpStatus == CifsExiting ||
server->tcpStatus == CifsNew ||
(server->ops->can_echo && !server->ops->can_echo(server)) ||
time_before(jiffies, server->lstrp + echo_interval - HZ))
time_before(jiffies, server->lstrp + server->echo_interval - HZ))
goto requeue_echo;

rc = server->ops->echo ? server->ops->echo(server) : -ENOSYS;
Expand Down Expand Up @@ -476,6 +466,7 @@ server_unresponsive(struct TCP_Server_Info *server)
*/
if ((server->tcpStatus == CifsGood ||
server->tcpStatus == CifsNeedNegotiate) &&
(!server->ops->can_echo || server->ops->can_echo(server)) &&
time_after(jiffies, server->lstrp + 3 * server->echo_interval)) {
cifs_server_dbg(VFS, "has not responded in %lu seconds. Reconnecting...\n",
(3 * server->echo_interval) / HZ);
Expand Down Expand Up @@ -3158,17 +3149,29 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
int
cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname)
{
int rc = 0;
int rc;

smb3_parse_devname(devname, ctx);
if (devname) {
cifs_dbg(FYI, "%s: devname=%s\n", __func__, devname);
rc = smb3_parse_devname(devname, ctx);
if (rc) {
cifs_dbg(VFS, "%s: failed to parse %s: %d\n", __func__, devname, rc);
return rc;
}
}

if (mntopts) {
char *ip;

cifs_dbg(FYI, "%s: mntopts=%s\n", __func__, mntopts);
rc = smb3_parse_opt(mntopts, "ip", &ip);
if (!rc && !cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip,
strlen(ip))) {
if (rc) {
cifs_dbg(VFS, "%s: failed to parse ip options: %d\n", __func__, rc);
return rc;
}

rc = cifs_convert_address((struct sockaddr *)&ctx->dstaddr, ip, strlen(ip));
kfree(ip);
if (!rc) {
cifs_dbg(VFS, "%s: failed to convert ip address\n", __func__);
return -EINVAL;
}
Expand All @@ -3188,7 +3191,7 @@ cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const c
return -EINVAL;
}

return rc;
return 0;
}

static int
Expand Down
10 changes: 10 additions & 0 deletions fs/cifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "cifs_fs_sb.h"
#include "cifs_unicode.h"
#include "fs_context.h"
#include "cifs_ioctl.h"

static void
renew_parental_timestamps(struct dentry *direntry)
Expand Down Expand Up @@ -430,6 +431,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
__u32 oplock;
struct cifsFileInfo *file_info;

if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
return -EIO;

/*
* Posix open is only called (at lookup time) for file create now. For
* opens (rather than creates), because we do not know if it is a file
Expand Down Expand Up @@ -546,6 +550,9 @@ int cifs_create(struct user_namespace *mnt_userns, struct inode *inode,
cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n",
inode, direntry, direntry);

if (unlikely(cifs_forced_shutdown(CIFS_SB(inode->i_sb))))
return -EIO;

tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
rc = PTR_ERR(tlink);
if (IS_ERR(tlink))
Expand Down Expand Up @@ -583,6 +590,9 @@ int cifs_mknod(struct user_namespace *mnt_userns, struct inode *inode,
return -EINVAL;

cifs_sb = CIFS_SB(inode->i_sb);
if (unlikely(cifs_forced_shutdown(cifs_sb)))
return -EIO;

tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
Expand Down
Loading

0 comments on commit 7c9e41e

Please sign in to comment.