'smb3 client fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmauj9AACgkQiiy9cAdy
 T1G4HgwAvdAPAn2BAFYT/SaXfkN3EX78mcGe85wA8CXQep7q/ik+3xAwvNMKOWmo
 OYmem3TqdfK4N4wkXCWd7TpKI+DZQAyt9ocIk8MhDWoIxp2A1nX/80SJUjTAJWvg
 8Q2HBZu8GfYyw8PW9KfR4hBOixvA8dLXZI7vNSvHP4S7XA10OP/HFTkwi4pPlkLF
 ZuSZNMU0Enwmzay1pUkVp9r2dq1ZDKtilbFFmN+bnuMoAigp//HDFFxx/zjIXCqb
 FdhA+bl9Wj1f2r164qDRHoVg2kVX2lyIzhQJtAWdIqxPEAfUgZCu//KN5NgdstYx
 sQID8DL0MDeDYRhvuoAVinLpLvJFVf0O4K43f5kY1HXA4JFn//lY9zPNE4FLuwrw
 Ez+WsB70YHhof14n5w1hgcDE5XMeLZLa3SbVNoyhTW4C7xjJj1cqMEfnqZTGUsLx
 s2sZJnLhoX0aThTp9+Wc4KLy9Z8QjOy3GMmc7tmCtwHfYJTocly8wfWCrR9VYvBP
 yVIhZCbt
 =MKOr
 -----END PGP SIGNATURE-----

Merge tag '6.11-rc1-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6

Pull smb client fixes from Steve French:

 - two reparse point fixes

 - minor cleanup

 - additional trace point (to help debug a recent problem)

* tag '6.11-rc1-smb-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: update internal version number
  smb: client: fix FSCTL_GET_REPARSE_POINT against NetApp
  smb3: add dynamic tracepoints for shutdown ioctl
  cifs: Remove cifs_aio_ctx
  smb: client: handle lack of FSCTL_GET_REPARSE_POINT support
This commit is contained in:
Linus Torvalds 2024-08-04 08:18:40 -07:00
commit 3f3f6d6123
10 changed files with 119 additions and 96 deletions

View File

@ -147,6 +147,6 @@ extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
/* when changing internal version - update following two lines at same time */
#define SMB3_PRODUCT_BUILD 49
#define CIFS_VERSION "2.49"
#define SMB3_PRODUCT_BUILD 50
#define CIFS_VERSION "2.50"
#endif /* _CIFSFS_H */

View File

@ -1471,29 +1471,6 @@ struct cifs_io_parms {
struct TCP_Server_Info *server;
};
struct cifs_aio_ctx {
struct kref refcount;
struct list_head list;
struct mutex aio_mutex;
struct completion done;
struct iov_iter iter;
struct kiocb *iocb;
struct cifsFileInfo *cfile;
struct bio_vec *bv;
loff_t pos;
unsigned int nr_pinned_pages;
ssize_t rc;
unsigned int len;
unsigned int total_len;
unsigned int bv_need_unpin; /* If ->bv[] needs unpinning */
bool should_dirty;
/*
* Indicates if this aio_ctx is for direct_io,
* If yes, iter is a copy of the user passed iov_iter
*/
bool direct_io;
};
struct cifs_io_request {
struct netfs_io_request rreq;
struct cifsFileInfo *cfile;
@ -2010,7 +1987,6 @@ require use of the stronger protocol */
* cifsFileInfo->file_info_lock cifsFileInfo->count cifs_new_fileinfo
* ->invalidHandle initiate_cifs_search
* ->oplock_break_cancelled
* cifs_aio_ctx->aio_mutex cifs_aio_ctx cifs_aio_ctx_alloc
****************************************************************************/
#ifdef DECLARE_GLOBALS_HERE

View File

@ -619,8 +619,6 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
struct shash_desc *shash);
enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
enum securityEnum);
struct cifs_aio_ctx *cifs_aio_ctx_alloc(void);
void cifs_aio_ctx_release(struct kref *refcount);
int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
void cifs_free_hash(struct shash_desc **sdesc);

View File

@ -1042,13 +1042,26 @@ static int reparse_info_to_fattr(struct cifs_open_info_data *data,
}
rc = -EOPNOTSUPP;
switch ((data->reparse.tag = tag)) {
case 0: /* SMB1 symlink */
data->reparse.tag = tag;
if (!data->reparse.tag) {
if (server->ops->query_symlink) {
rc = server->ops->query_symlink(xid, tcon,
cifs_sb, full_path,
&data->symlink_target);
}
if (rc == -EOPNOTSUPP)
data->reparse.tag = IO_REPARSE_TAG_INTERNAL;
}
switch (data->reparse.tag) {
case 0: /* SMB1 symlink */
break;
case IO_REPARSE_TAG_INTERNAL:
rc = 0;
if (le32_to_cpu(data->fi.Attributes) & ATTR_DIRECTORY) {
cifs_create_junction_fattr(fattr, sb);
goto out;
}
break;
case IO_REPARSE_TAG_MOUNT_POINT:
cifs_create_junction_fattr(fattr, sb);

View File

@ -170,7 +170,10 @@ static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
static int cifs_shutdown(struct super_block *sb, unsigned long arg)
{
struct cifs_sb_info *sbi = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *tcon;
__u32 flags;
int rc;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@ -178,14 +181,21 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
if (get_user(flags, (__u32 __user *)arg))
return -EFAULT;
if (flags > CIFS_GOING_FLAGS_NOLOGFLUSH)
return -EINVAL;
tlink = cifs_sb_tlink(sbi);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
trace_smb3_shutdown_enter(flags, tcon->tid);
if (flags > CIFS_GOING_FLAGS_NOLOGFLUSH) {
rc = -EINVAL;
goto shutdown_out_err;
}
if (cifs_forced_shutdown(sbi))
return 0;
goto shutdown_good;
cifs_dbg(VFS, "shut down requested (%d)", flags);
/* trace_cifs_shutdown(sb, flags);*/
/*
* see:
@ -201,7 +211,8 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
*/
case CIFS_GOING_FLAGS_DEFAULT:
cifs_dbg(FYI, "shutdown with default flag not supported\n");
return -EINVAL;
rc = -EINVAL;
goto shutdown_out_err;
/*
* FLAGS_LOGFLUSH is easy since it asks to write out metadata (not
* data) but metadata writes are not cached on the client, so can treat
@ -210,11 +221,18 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
case CIFS_GOING_FLAGS_LOGFLUSH:
case CIFS_GOING_FLAGS_NOLOGFLUSH:
sbi->mnt_cifs_flags |= CIFS_MOUNT_SHUTDOWN;
return 0;
goto shutdown_good;
default:
return -EINVAL;
rc = -EINVAL;
goto shutdown_out_err;
}
shutdown_good:
trace_smb3_shutdown_done(flags, tcon->tid);
return 0;
shutdown_out_err:
trace_smb3_shutdown_err(rc, flags, tcon->tid);
return rc;
}
static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug_info __user *in)

View File

@ -995,60 +995,6 @@ parse_DFS_referrals_exit:
return rc;
}
struct cifs_aio_ctx *
cifs_aio_ctx_alloc(void)
{
struct cifs_aio_ctx *ctx;
/*
* Must use kzalloc to initialize ctx->bv to NULL and ctx->direct_io
* to false so that we know when we have to unreference pages within
* cifs_aio_ctx_release()
*/
ctx = kzalloc(sizeof(struct cifs_aio_ctx), GFP_KERNEL);
if (!ctx)
return NULL;
INIT_LIST_HEAD(&ctx->list);
mutex_init(&ctx->aio_mutex);
init_completion(&ctx->done);
kref_init(&ctx->refcount);
return ctx;
}
void
cifs_aio_ctx_release(struct kref *refcount)
{
struct cifs_aio_ctx *ctx = container_of(refcount,
struct cifs_aio_ctx, refcount);
cifsFileInfo_put(ctx->cfile);
/*
* ctx->bv is only set if setup_aio_ctx_iter() was call successfuly
* which means that iov_iter_extract_pages() was a success and thus
* that we may have references or pins on pages that we need to
* release.
*/
if (ctx->bv) {
if (ctx->should_dirty || ctx->bv_need_unpin) {
unsigned int i;
for (i = 0; i < ctx->nr_pinned_pages; i++) {
struct page *page = ctx->bv[i].bv_page;
if (ctx->should_dirty)
set_page_dirty(page);
if (ctx->bv_need_unpin)
unpin_user_page(page);
}
}
kvfree(ctx->bv);
}
kfree(ctx);
}
/**
* cifs_alloc_hash - allocate hash and hash context together
* @name: The name of the crypto hash algo

View File

@ -505,6 +505,10 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
}
switch (tag) {
case IO_REPARSE_TAG_INTERNAL:
if (!(fattr->cf_cifsattrs & ATTR_DIRECTORY))
return false;
fallthrough;
case IO_REPARSE_TAG_DFS:
case IO_REPARSE_TAG_DFSR:
case IO_REPARSE_TAG_MOUNT_POINT:

View File

@ -12,6 +12,12 @@
#include "fs_context.h"
#include "cifsglob.h"
/*
* Used only by cifs.ko to ignore reparse points from files when client or
* server doesn't support FSCTL_GET_REPARSE_POINT.
*/
#define IO_REPARSE_TAG_INTERNAL ((__u32)~0U)
static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf)
{
u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer);
@ -78,10 +84,19 @@ static inline u32 reparse_mode_wsl_tag(mode_t mode)
static inline bool reparse_inode_match(struct inode *inode,
struct cifs_fattr *fattr)
{
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct timespec64 ctime = inode_get_ctime(inode);
return (CIFS_I(inode)->cifsAttrs & ATTR_REPARSE) &&
CIFS_I(inode)->reparse_tag == fattr->cf_cifstag &&
/*
* Do not match reparse tags when client or server doesn't support
* FSCTL_GET_REPARSE_POINT. @fattr->cf_cifstag should contain correct
* reparse tag from query dir response but the client won't be able to
* read the reparse point data anyway. This spares us a revalidation.
*/
if (cinode->reparse_tag != IO_REPARSE_TAG_INTERNAL &&
cinode->reparse_tag != fattr->cf_cifstag)
return false;
return (cinode->cifsAttrs & ATTR_REPARSE) &&
timespec64_equal(&ctime, &fattr->cf_ctime);
}

View File

@ -930,6 +930,8 @@ int smb2_query_path_info(const unsigned int xid,
switch (rc) {
case 0:
rc = parse_create_response(data, cifs_sb, &out_iov[0]);
break;
case -EOPNOTSUPP:
/*
* BB TODO: When support for special files added to Samba
@ -948,7 +950,8 @@ int smb2_query_path_info(const unsigned int xid,
cmds[num_cmds++] = SMB2_OP_GET_REPARSE;
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_READ_ATTRIBUTES |
FILE_READ_EA | SYNCHRONIZE,
FILE_OPEN, create_options |
OPEN_REPARSE_POINT, ACL_NO_MODE);
cifs_get_readable_path(tcon, full_path, &cfile);
@ -1256,7 +1259,8 @@ int smb2_query_reparse_point(const unsigned int xid,
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
cifs_get_readable_path(tcon, full_path, &cfile);
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, FILE_READ_ATTRIBUTES,
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path,
FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
FILE_OPEN, OPEN_REPARSE_POINT, ACL_NO_MODE);
rc = smb2_compound_op(xid, tcon, cifs_sb,
full_path, &oparms, &in_iov,

View File

@ -1388,7 +1388,7 @@ DECLARE_EVENT_CLASS(smb3_ioctl_class,
__entry->command = command;
),
TP_printk("xid=%u fid=0x%llx ioctl cmd=0x%x",
__entry->xid, __entry->fid, __entry->command)
__entry->xid, __entry->fid, __entry->command)
)
#define DEFINE_SMB3_IOCTL_EVENT(name) \
@ -1400,9 +1400,58 @@ DEFINE_EVENT(smb3_ioctl_class, smb3_##name, \
DEFINE_SMB3_IOCTL_EVENT(ioctl);
DECLARE_EVENT_CLASS(smb3_shutdown_class,
TP_PROTO(__u32 flags,
__u32 tid),
TP_ARGS(flags, tid),
TP_STRUCT__entry(
__field(__u32, flags)
__field(__u32, tid)
),
TP_fast_assign(
__entry->flags = flags;
__entry->tid = tid;
),
TP_printk("flags=0x%x tid=0x%x",
__entry->flags, __entry->tid)
)
#define DEFINE_SMB3_SHUTDOWN_EVENT(name) \
DEFINE_EVENT(smb3_shutdown_class, smb3_##name, \
TP_PROTO(__u32 flags, \
__u32 tid), \
TP_ARGS(flags, tid))
DEFINE_SMB3_SHUTDOWN_EVENT(shutdown_enter);
DEFINE_SMB3_SHUTDOWN_EVENT(shutdown_done);
DECLARE_EVENT_CLASS(smb3_shutdown_err_class,
TP_PROTO(int rc,
__u32 flags,
__u32 tid),
TP_ARGS(rc, flags, tid),
TP_STRUCT__entry(
__field(int, rc)
__field(__u32, flags)
__field(__u32, tid)
),
TP_fast_assign(
__entry->rc = rc;
__entry->flags = flags;
__entry->tid = tid;
),
TP_printk("rc=%d flags=0x%x tid=0x%x",
__entry->rc, __entry->flags, __entry->tid)
)
#define DEFINE_SMB3_SHUTDOWN_ERR_EVENT(name) \
DEFINE_EVENT(smb3_shutdown_err_class, smb3_##name, \
TP_PROTO(int rc, \
__u32 flags, \
__u32 tid), \
TP_ARGS(rc, flags, tid))
DEFINE_SMB3_SHUTDOWN_ERR_EVENT(shutdown_err);
DECLARE_EVENT_CLASS(smb3_credit_class,
TP_PROTO(__u64 currmid,