Commit daad00c0 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull smb client fixes from Steve French:

 - fix posix mkdir error to ksmbd (also avoids crash in
   cifs_destroy_request_bufs)

 - two smb1 fixes: fixing querypath info and setpathinfo to old servers

 - fix rsize/wsize when not multiple of page size to address DIO
   reads/writes

* tag '6.15-rc4-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
  smb: client: ensure aligned IO sizes
  cifs: Fix changing times and read-only attr over SMB1 smb_set_file_info() function
  cifs: Fix and improve cifs_query_path_info() and cifs_query_file_info()
  smb: client: fix zero length for mkdir POSIX create context
parents 6de6674c c59f7c96
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -1266,10 +1266,9 @@ typedef struct smb_com_query_information_rsp {
typedef struct smb_com_setattr_req {
	struct smb_hdr hdr; /* wct = 8 */
	__le16 attr;
	__le16 time_low;
	__le16 time_high;
	__le32 last_write_time;
	__le16 reserved[5]; /* must be zero */
	__u16  ByteCount;
	__le16 ByteCount;
	__u8   BufferFormat; /* 4 = ASCII */
	unsigned char fileName[];
} __attribute__((packed)) SETATTR_REQ;
+4 −0
Original line number Diff line number Diff line
@@ -395,6 +395,10 @@ extern int CIFSSMBQFSUnixInfo(const unsigned int xid, struct cifs_tcon *tcon);
extern int CIFSSMBQFSPosixInfo(const unsigned int xid, struct cifs_tcon *tcon,
			struct kstatfs *FSData);

extern int SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
			     const char *fileName, __le32 attributes, __le64 write_time,
			     const struct nls_table *nls_codepage,
			     struct cifs_sb_info *cifs_sb);
extern int CIFSSMBSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
			const char *fileName, const FILE_BASIC_INFO *data,
			const struct nls_table *nls_codepage,
+57 −0
Original line number Diff line number Diff line
@@ -5171,6 +5171,63 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
	return rc;
}

int
SMBSetInformation(const unsigned int xid, struct cifs_tcon *tcon,
		  const char *fileName, __le32 attributes, __le64 write_time,
		  const struct nls_table *nls_codepage,
		  struct cifs_sb_info *cifs_sb)
{
	SETATTR_REQ *pSMB;
	SETATTR_RSP *pSMBr;
	struct timespec64 ts;
	int bytes_returned;
	int name_len;
	int rc;

	cifs_dbg(FYI, "In %s path %s\n", __func__, fileName);

retry:
	rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
		      (void **) &pSMBr);
	if (rc)
		return rc;

	if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
		name_len =
			cifsConvertToUTF16((__le16 *) pSMB->fileName,
					   fileName, PATH_MAX, nls_codepage,
					   cifs_remap(cifs_sb));
		name_len++;     /* trailing null */
		name_len *= 2;
	} else {
		name_len = copy_path_name(pSMB->fileName, fileName);
	}
	/* Only few attributes can be set by this command, others are not accepted by Win9x. */
	pSMB->attr = cpu_to_le16(le32_to_cpu(attributes) &
			(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE));
	/* Zero write time value (in both NT and SETATTR formats) means to not change it. */
	if (le64_to_cpu(write_time) != 0) {
		ts = cifs_NTtimeToUnix(write_time);
		pSMB->last_write_time = cpu_to_le32(ts.tv_sec);
	}
	pSMB->BufferFormat = 0x04;
	name_len++; /* account for buffer type byte */
	inc_rfc1001_len(pSMB, (__u16)name_len);
	pSMB->ByteCount = cpu_to_le16(name_len);

	rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
	if (rc)
		cifs_dbg(FYI, "Send error in %s = %d\n", __func__, rc);

	cifs_buf_release(pSMB);

	if (rc == -EAGAIN)
		goto retry;

	return rc;
}

/* Some legacy servers such as NT4 require that the file times be set on
   an open handle, rather than by pathname - this is awkward due to
   potential access conflicts on the open, but it is unavoidable for these
+1 −22
Original line number Diff line number Diff line
@@ -3753,28 +3753,7 @@ int cifs_mount_get_tcon(struct cifs_mount_ctx *mnt_ctx)
		}
	}

	/*
	 * Clamp the rsize/wsize mount arguments if they are too big for the server
	 * and set the rsize/wsize to the negotiated values if not passed in by
	 * the user on mount
	 */
	if ((cifs_sb->ctx->wsize == 0) ||
	    (cifs_sb->ctx->wsize > server->ops->negotiate_wsize(tcon, ctx))) {
		cifs_sb->ctx->wsize =
			round_down(server->ops->negotiate_wsize(tcon, ctx), PAGE_SIZE);
		/*
		 * in the very unlikely event that the server sent a max write size under PAGE_SIZE,
		 * (which would get rounded down to 0) then reset wsize to absolute minimum eg 4096
		 */
		if (cifs_sb->ctx->wsize == 0) {
			cifs_sb->ctx->wsize = PAGE_SIZE;
			cifs_dbg(VFS, "wsize too small, reset to minimum ie PAGE_SIZE, usually 4096\n");
		}
	}
	if ((cifs_sb->ctx->rsize == 0) ||
	    (cifs_sb->ctx->rsize > server->ops->negotiate_rsize(tcon, ctx)))
		cifs_sb->ctx->rsize = server->ops->negotiate_rsize(tcon, ctx);

	cifs_negotiate_iosize(server, cifs_sb->ctx, tcon);
	/*
	 * The cookie is initialized from volume info returned above.
	 * Inside cifs_fscache_get_super_cookie it checks
+2 −4
Original line number Diff line number Diff line
@@ -160,10 +160,8 @@ static int cifs_prepare_read(struct netfs_io_subrequest *subreq)
	server = cifs_pick_channel(tlink_tcon(req->cfile->tlink)->ses);
	rdata->server = server;

	if (cifs_sb->ctx->rsize == 0)
		cifs_sb->ctx->rsize =
			server->ops->negotiate_rsize(tlink_tcon(req->cfile->tlink),
						     cifs_sb->ctx);
	cifs_negotiate_rsize(server, cifs_sb->ctx,
			     tlink_tcon(req->cfile->tlink));

	rc = server->ops->wait_mtu_credits(server, cifs_sb->ctx->rsize,
					   &size, &rdata->credits);
Loading