Skip to content

Commit

Permalink
Merge tag '6.11-rc1-smb-client-fixes' of git://git.samba.org/sfrench/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
torvalds committed Aug 4, 2024
2 parents 3c41df4 + a91bfa6 commit 3f3f6d6
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 96 deletions.
4 changes: 2 additions & 2 deletions fs/smb/client/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
24 changes: 0 additions & 24 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 0 additions & 2 deletions fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
17 changes: 15 additions & 2 deletions fs/smb/client/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
32 changes: 25 additions & 7 deletions fs/smb/client/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,22 +170,32 @@ 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;

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:
Expand All @@ -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
Expand All @@ -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)
Expand Down
54 changes: 0 additions & 54 deletions fs/smb/client/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -995,60 +995,6 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
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
Expand Down
4 changes: 4 additions & 0 deletions fs/smb/client/reparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
19 changes: 17 additions & 2 deletions fs/smb/client/reparse.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
8 changes: 6 additions & 2 deletions fs/smb/client/smb2inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
51 changes: 50 additions & 1 deletion fs/smb/client/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand All @@ -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,
Expand Down

0 comments on commit 3f3f6d6

Please sign in to comment.