* [PATCH 01/45] CIFS: Make CAP_* checks protocol independent
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-2-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 02/45] CIFS: Simpliify cifs_mkdir call Pavel Shilovsky
` (44 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Since both CIFS and SMB2 use ses->capabilities (server->capabilities)
field but flags are different we should make such checks protocol
independent.
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 10 ++++++++++
fs/cifs/connect.c | 6 +++---
fs/cifs/dir.c | 3 +--
fs/cifs/file.c | 33 ++++++++++++++++-----------------
fs/cifs/inode.c | 26 ++++++++++++--------------
fs/cifs/link.c | 6 +++---
fs/cifs/readdir.c | 16 ++++++++--------
fs/cifs/smb1ops.c | 3 +++
fs/cifs/smb2ops.c | 3 +++
fs/cifs/smb2pdu.c | 2 ++
fs/cifs/smb2pdu.h | 3 +++
11 files changed, 64 insertions(+), 47 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 12b1176..5695693 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -258,6 +258,9 @@ struct smb_version_values {
size_t max_header_size;
size_t read_rsp_size;
__le16 lock_cmd;
+ int cap_unix;
+ int cap_nt_find;
+ int cap_large_files;
};
#define HEADER_SIZE(server) (server->vals->header_size)
@@ -554,6 +557,13 @@ struct cifs_ses {
which do not negotiate NTLM or POSIX dialects, but instead
negotiate one of the older LANMAN dialects */
#define CIFS_SES_LANMAN 8
+
+static inline bool
+cap_unix(struct cifs_ses *ses)
+{
+ return ses->server->vals->cap_unix & ses->capabilities;
+}
+
/*
* there is one of these for each connection to a resource on a particular
* session
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index b1ab89a..99d50bf 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3633,7 +3633,7 @@ try_mount_again:
}
/* tell server which Unix caps we support */
- if (tcon->ses->capabilities & CAP_UNIX) {
+ if (cap_unix(tcon->ses)) {
/* reset of caps checks mount to see if unix extensions
disabled for just this mount */
reset_cifs_unix_caps(xid, tcon, cifs_sb, volume_info);
@@ -3992,7 +3992,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
ses->flags = 0;
ses->capabilities = server->capabilities;
if (linuxExtEnabled == 0)
- ses->capabilities &= (~CAP_UNIX);
+ ses->capabilities &= (~server->vals->cap_unix);
cFYI(1, "Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
server->sec_mode, server->capabilities, server->timeAdj);
@@ -4099,7 +4099,7 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
goto out;
}
- if (ses->capabilities & CAP_UNIX)
+ if (cap_unix(ses))
reset_cifs_unix_caps(0, tcon, NULL, vol_info);
out:
kfree(vol_info->username);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 2caba0b..cbe709a 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -182,8 +182,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
goto out;
}
- if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
- !tcon->broken_posix_open &&
+ if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = cifs_posix_open(full_path, &newinode,
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ea1bb66..1712794 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -385,9 +385,8 @@ int cifs_open(struct inode *inode, struct file *file)
oplock = 0;
if (!tcon->broken_posix_open && tcon->unix_ext &&
- (tcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_POSIX_PATH_OPS_CAP &
- le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+ cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
/* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */,
@@ -509,10 +508,9 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
else
oplock = 0;
- if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+ if (tcon->unix_ext && cap_unix(tcon->ses) &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
- le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
/*
* O_CREAT, O_EXCL and O_TRUNC already had their effect on the
* original open. Must mask them off for a reopen.
@@ -1073,7 +1071,7 @@ cifs_push_locks(struct cifsFileInfo *cfile)
struct cifs_sb_info *cifs_sb = CIFS_SB(cfile->dentry->d_sb);
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
- if ((tcon->ses->capabilities & CAP_UNIX) &&
+ if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
return cifs_push_posix_locks(cfile);
@@ -1421,7 +1419,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
netfid = cfile->netfid;
cinode = CIFS_I(file->f_path.dentry->d_inode);
- if ((tcon->ses->capabilities & CAP_UNIX) &&
+ if (cap_unix(tcon->ses) &&
(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) &&
((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
posix_lck = true;
@@ -2747,7 +2745,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
unsigned int current_read_size;
unsigned int rsize;
struct cifs_sb_info *cifs_sb;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
unsigned int xid;
char *current_offset;
struct cifsFileInfo *open_file;
@@ -2767,7 +2765,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return rc;
}
open_file = file->private_data;
- pTcon = tlink_tcon(open_file->tlink);
+ tcon = tlink_tcon(open_file->tlink);
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
pid = open_file->pid;
@@ -2781,11 +2779,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
read_size > total_read;
total_read += bytes_read, current_offset += bytes_read) {
current_read_size = min_t(uint, read_size - total_read, rsize);
-
- /* For windows me and 9x we do not want to request more
- than it negotiated since it will refuse the read then */
- if ((pTcon->ses) &&
- !(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
+ /*
+ * For windows me and 9x we do not want to request more than it
+ * negotiated since it will refuse the read then.
+ */
+ if ((tcon->ses) && !(tcon->ses->capabilities |
+ tcon->ses->server->vals->cap_large_files)) {
current_read_size = min_t(uint, current_read_size,
CIFSMaxBufSize);
}
@@ -2798,7 +2797,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
}
io_parms.netfid = open_file->netfid;
io_parms.pid = pid;
- io_parms.tcon = pTcon;
+ io_parms.tcon = tcon;
io_parms.offset = *poffset;
io_parms.length = current_read_size;
rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
@@ -2812,7 +2811,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
return rc;
}
} else {
- cifs_stats_bytes_read(pTcon, total_read);
+ cifs_stats_bytes_read(tcon, total_read);
*poffset += bytes_read;
}
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index def1006..35cb6a3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1149,9 +1149,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
goto unlink_out;
}
- if ((tcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_POSIX_PATH_OPS_CAP &
- le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+ if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
rc = CIFSPOSIXDelFile(xid, tcon, full_path,
SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1226,7 +1225,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
unsigned int xid;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
char *full_path = NULL;
struct inode *newinode = NULL;
struct cifs_fattr fattr;
@@ -1237,7 +1236,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
xid = get_xid();
@@ -1247,9 +1246,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}
- if ((pTcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_POSIX_PATH_OPS_CAP &
- le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+ if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(tcon->fsUnixInfo.Capability))) {
u32 oplock = 0;
FILE_UNIX_BASIC_INFO *pInfo =
kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
@@ -1259,7 +1257,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
}
mode &= ~current_umask();
- rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+ rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
mode, NULL /* netfid */, pInfo, &oplock,
full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -1303,14 +1301,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
}
mkdir_retry_old:
/* BB add setting the equivalent of mode via CreateX w/ACLs */
- rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
+ rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cFYI(1, "cifs_mkdir returned 0x%x", rc);
d_drop(direntry);
} else {
mkdir_get_info:
- if (pTcon->unix_ext)
+ if (tcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid);
else
@@ -1328,7 +1326,7 @@ mkdir_get_info:
if (inode->i_mode & S_ISGID)
mode |= S_ISGID;
- if (pTcon->unix_ext) {
+ if (tcon->unix_ext) {
struct cifs_unix_set_info_args args = {
.mode = mode,
.ctime = NO_CHANGE_64,
@@ -1346,7 +1344,7 @@ mkdir_get_info:
args.uid = NO_CHANGE_64;
args.gid = NO_CHANGE_64;
}
- CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args,
+ CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1361,7 +1359,7 @@ mkdir_get_info:
cifsInode = CIFS_I(newinode);
dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
pInfo.Attributes = cpu_to_le32(dosattrs);
- tmprc = CIFSSMBSetPathInfo(xid, pTcon,
+ tmprc = CIFSSMBSetPathInfo(xid, tcon,
full_path, &pInfo,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 77d781a..d08b76c 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -495,8 +495,8 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
* but there doesn't seem to be any harm in allowing the client to
* read them.
*/
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS)
- && !(tcon->ses->capabilities & CAP_UNIX)) {
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
+ !cap_unix(tcon->ses)) {
rc = -EACCES;
goto out;
}
@@ -518,7 +518,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if ((rc != 0) && (tcon->ses->capabilities & CAP_UNIX))
+ if ((rc != 0) && cap_unix(tcon->ses))
rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
cifs_sb->local_nls);
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index da30d96..d87f826 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -228,7 +228,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
struct cifsFileInfo *cifsFile;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
struct tcon_link *tlink = NULL;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
if (file->private_data == NULL) {
tlink = cifs_sb_tlink(cifs_sb);
@@ -242,10 +242,10 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
}
file->private_data = cifsFile;
cifsFile->tlink = cifs_get_tlink(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
} else {
cifsFile = file->private_data;
- pTcon = tlink_tcon(cifsFile->tlink);
+ tcon = tlink_tcon(cifsFile->tlink);
}
cifsFile->invalidHandle = true;
@@ -262,11 +262,11 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
ffirst_retry:
/* test for Unix extensions */
/* but now check for them on the share/mount not on the SMB session */
-/* if (pTcon->ses->capabilities & CAP_UNIX) { */
- if (pTcon->unix_ext)
+ /* if (cap_unix(tcon->ses) { */
+ if (tcon->unix_ext)
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
- else if ((pTcon->ses->capabilities &
- (CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
+ else if ((tcon->ses->capabilities &
+ tcon->ses->server->vals->cap_nt_find) == 0) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
@@ -278,7 +278,7 @@ ffirst_retry:
if (backup_cred(cifs_sb))
search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
- rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
+ rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
&cifsFile->netfid, search_flags, &cifsFile->srch_inf,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 5817409..c40356d 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -632,4 +632,7 @@ struct smb_version_values smb1_values = {
.max_header_size = MAX_CIFS_HDR_SIZE,
.read_rsp_size = sizeof(READ_RSP),
.lock_cmd = cpu_to_le16(SMB_COM_LOCKING_ANDX),
+ .cap_unix = CAP_UNIX,
+ .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
+ .cap_large_files = CAP_LARGE_FILES,
};
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 1018c5c..410cf92 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -325,4 +325,7 @@ struct smb_version_values smb21_values = {
.header_size = sizeof(struct smb2_hdr),
.max_header_size = MAX_SMB2_HDR_SIZE,
.lock_cmd = SMB2_LOCK,
+ .cap_unix = 0,
+ .cap_nt_find = SMB2_NT_FIND,
+ .cap_large_files = SMB2_LARGE_FILES,
};
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index e4eb1d3..62b3f17 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -428,6 +428,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
/* BB Do we need to validate the SecurityMode? */
server->sec_mode = le16_to_cpu(rsp->SecurityMode);
server->capabilities = le32_to_cpu(rsp->Capabilities);
+ /* Internal types */
+ server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
&rsp->hdr);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 59aae60..f37a1b4 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -167,6 +167,9 @@ struct smb2_negotiate_req {
#define SMB2_GLOBAL_CAP_DFS 0x00000001
#define SMB2_GLOBAL_CAP_LEASING 0x00000002 /* Resp only New to SMB2.1 */
#define SMB2_GLOBAL_CAP_LARGE_MTU 0X00000004 /* Resp only New to SMB2.1 */
+/* Internal types */
+#define SMB2_NT_FIND 0x00100000
+#define SMB2_LARGE_FILES 0x00200000
struct smb2_negotiate_rsp {
struct smb2_hdr hdr;
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 02/45] CIFS: Simpliify cifs_mkdir call
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 01/45] CIFS: Make CAP_* checks protocol independent Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-3-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 03/45] CIFS: Separate protocol specific part from mkdir Pavel Shilovsky
` (43 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsproto.h | 4 +-
fs/cifs/cifssmb.c | 8 +-
fs/cifs/inode.c | 295 ++++++++++++++++++++++++++++-----------------------
3 files changed, 167 insertions(+), 140 deletions(-)
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5aadeec..51fbdf2 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -289,10 +289,10 @@ extern int CIFSSMBUnixSetFileInfo(const unsigned int xid,
u16 fid, u32 pid_of_opener);
extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
- struct cifs_tcon *tcon, char *file_name,
+ struct cifs_tcon *tcon, const char *file_name,
const struct cifs_unix_set_info_args *args,
const struct nls_table *nls_codepage,
- int remap_special_chars);
+ int remap);
extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
const char *newName,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 846b803..ed472aa 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5945,7 +5945,7 @@ CIFSSMBUnixSetFileInfo(const unsigned int xid, struct cifs_tcon *tcon,
int
CIFSSMBUnixSetPathInfo(const unsigned int xid, struct cifs_tcon *tcon,
- char *fileName,
+ const char *file_name,
const struct cifs_unix_set_info_args *args,
const struct nls_table *nls_codepage, int remap)
{
@@ -5966,14 +5966,14 @@ setPermsRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
+ cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
+ name_len = strnlen(file_name, PATH_MAX);
name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
+ strncpy(pSMB->FileName, file_name, name_len);
}
params = 6 + name_len;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 35cb6a3..e9ba1a1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1219,16 +1219,165 @@ unlink_out:
return rc;
}
+static int
+cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
+ const char *full_path, struct cifs_sb_info *cifs_sb,
+ struct cifs_tcon *tcon, const unsigned int xid)
+{
+ int rc = 0;
+ struct inode *newinode = NULL;
+
+ if (tcon->unix_ext)
+ rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+ xid);
+ else
+ rc = cifs_get_inode_info(&newinode, full_path, NULL,
+ inode->i_sb, xid, NULL);
+ if (rc)
+ return rc;
+
+ d_instantiate(dentry, newinode);
+ /*
+ * setting nlink not necessary except in cases where we failed to get it
+ * from the server or was set bogus
+ */
+ if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
+ set_nlink(dentry->d_inode, 2);
+
+ mode &= ~current_umask();
+ /* must turn on setgid bit if parent dir has it */
+ if (inode->i_mode & S_ISGID)
+ mode |= S_ISGID;
+
+ if (tcon->unix_ext) {
+ struct cifs_unix_set_info_args args = {
+ .mode = mode,
+ .ctime = NO_CHANGE_64,
+ .atime = NO_CHANGE_64,
+ .mtime = NO_CHANGE_64,
+ .device = 0,
+ };
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ args.uid = (__u64)current_fsuid();
+ if (inode->i_mode & S_ISGID)
+ args.gid = (__u64)inode->i_gid;
+ else
+ args.gid = (__u64)current_fsgid();
+ } else {
+ args.uid = NO_CHANGE_64;
+ args.gid = NO_CHANGE_64;
+ }
+ CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ } else {
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
+ (mode & S_IWUGO) == 0) {
+ FILE_BASIC_INFO info;
+ struct cifsInodeInfo *cifsInode;
+ u32 dosattrs;
+ int tmprc;
+
+ memset(&info, 0, sizeof(info));
+ cifsInode = CIFS_I(newinode);
+ dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+ info.Attributes = cpu_to_le32(dosattrs);
+ tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (tmprc == 0)
+ cifsInode->cifsAttrs = dosattrs;
+ }
+ if (dentry->d_inode) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+ dentry->d_inode->i_mode = (mode | S_IFDIR);
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+ dentry->d_inode->i_uid = current_fsuid();
+ if (inode->i_mode & S_ISGID)
+ dentry->d_inode->i_gid = inode->i_gid;
+ else
+ dentry->d_inode->i_gid =
+ current_fsgid();
+ }
+ }
+ }
+ return rc;
+}
+
+static int
+cifs_posix_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode,
+ const char *full_path, struct cifs_sb_info *cifs_sb,
+ struct cifs_tcon *tcon, const unsigned int xid)
+{
+ int rc = 0;
+ u32 oplock = 0;
+ FILE_UNIX_BASIC_INFO *info = NULL;
+ struct inode *newinode = NULL;
+ struct cifs_fattr fattr;
+
+ info = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ if (info == NULL) {
+ rc = -ENOMEM;
+ goto posix_mkdir_out;
+ }
+
+ mode &= ~current_umask();
+ rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode,
+ NULL /* netfid */, info, &oplock, full_path,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == -EOPNOTSUPP)
+ goto posix_mkdir_out;
+ else if (rc) {
+ cFYI(1, "posix mkdir returned 0x%x", rc);
+ d_drop(dentry);
+ goto posix_mkdir_out;
+ }
+
+ if (info->Type == cpu_to_le32(-1))
+ /* no return info, go query for it */
+ goto posix_mkdir_get_info;
+ /*
+ * BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if
+ * need to set uid/gid.
+ */
+
+ cifs_unix_basic_to_fattr(&fattr, info, cifs_sb);
+ cifs_fill_uniqueid(inode->i_sb, &fattr);
+ newinode = cifs_iget(inode->i_sb, &fattr);
+ if (!newinode)
+ goto posix_mkdir_get_info;
+
+ d_instantiate(dentry, newinode);
+
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1, "instantiated dentry %p %s to inode %p", dentry,
+ dentry->d_name.name, newinode);
+
+ if (newinode->i_nlink != 2)
+ cFYI(1, "unexpected number of links %d", newinode->i_nlink);
+#endif
+
+posix_mkdir_out:
+ kfree(info);
+ return rc;
+posix_mkdir_get_info:
+ rc = cifs_mkdir_qinfo(inode, dentry, mode, full_path, cifs_sb, tcon,
+ xid);
+ goto posix_mkdir_out;
+}
+
int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
{
- int rc = 0, tmprc;
+ int rc = 0;
unsigned int xid;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
- char *full_path = NULL;
- struct inode *newinode = NULL;
- struct cifs_fattr fattr;
+ char *full_path;
cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
@@ -1248,145 +1397,23 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
- u32 oplock = 0;
- FILE_UNIX_BASIC_INFO *pInfo =
- kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
- if (pInfo == NULL) {
- rc = -ENOMEM;
+ rc = cifs_posix_mkdir(inode, direntry, mode, full_path, cifs_sb,
+ tcon, xid);
+ if (rc != -EOPNOTSUPP)
goto mkdir_out;
- }
-
- mode &= ~current_umask();
- rc = CIFSPOSIXCreate(xid, tcon, SMB_O_DIRECTORY | SMB_O_CREAT,
- mode, NULL /* netfid */, pInfo, &oplock,
- full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == -EOPNOTSUPP) {
- kfree(pInfo);
- goto mkdir_retry_old;
- } else if (rc) {
- cFYI(1, "posix mkdir returned 0x%x", rc);
- d_drop(direntry);
- } else {
- if (pInfo->Type == cpu_to_le32(-1)) {
- /* no return info, go query for it */
- kfree(pInfo);
- goto mkdir_get_info;
- }
-/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
- to set uid/gid */
-
- cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb);
- cifs_fill_uniqueid(inode->i_sb, &fattr);
- newinode = cifs_iget(inode->i_sb, &fattr);
- if (!newinode) {
- kfree(pInfo);
- goto mkdir_get_info;
- }
-
- d_instantiate(direntry, newinode);
-
-#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1, "instantiated dentry %p %s to inode %p",
- direntry, direntry->d_name.name, newinode);
-
- if (newinode->i_nlink != 2)
- cFYI(1, "unexpected number of links %d",
- newinode->i_nlink);
-#endif
- }
- kfree(pInfo);
- goto mkdir_out;
}
-mkdir_retry_old:
+
/* BB add setting the equivalent of mode via CreateX w/ACLs */
rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cFYI(1, "cifs_mkdir returned 0x%x", rc);
d_drop(direntry);
- } else {
-mkdir_get_info:
- if (tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb, xid);
- else
- rc = cifs_get_inode_info(&newinode, full_path, NULL,
- inode->i_sb, xid, NULL);
-
- d_instantiate(direntry, newinode);
- /* setting nlink not necessary except in cases where we
- * failed to get it from the server or was set bogus */
- if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
- set_nlink(direntry->d_inode, 2);
-
- mode &= ~current_umask();
- /* must turn on setgid bit if parent dir has it */
- if (inode->i_mode & S_ISGID)
- mode |= S_ISGID;
-
- if (tcon->unix_ext) {
- struct cifs_unix_set_info_args args = {
- .mode = mode,
- .ctime = NO_CHANGE_64,
- .atime = NO_CHANGE_64,
- .mtime = NO_CHANGE_64,
- .device = 0,
- };
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
- args.uid = (__u64)current_fsuid();
- if (inode->i_mode & S_ISGID)
- args.gid = (__u64)inode->i_gid;
- else
- args.gid = (__u64)current_fsgid();
- } else {
- args.uid = NO_CHANGE_64;
- args.gid = NO_CHANGE_64;
- }
- CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else {
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
- (mode & S_IWUGO) == 0) {
- FILE_BASIC_INFO pInfo;
- struct cifsInodeInfo *cifsInode;
- u32 dosattrs;
-
- memset(&pInfo, 0, sizeof(pInfo));
- cifsInode = CIFS_I(newinode);
- dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
- pInfo.Attributes = cpu_to_le32(dosattrs);
- tmprc = CIFSSMBSetPathInfo(xid, tcon,
- full_path, &pInfo,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (tmprc == 0)
- cifsInode->cifsAttrs = dosattrs;
- }
- if (direntry->d_inode) {
- if (cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_DYNPERM)
- direntry->d_inode->i_mode =
- (mode | S_IFDIR);
-
- if (cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_SET_UID) {
- direntry->d_inode->i_uid =
- current_fsuid();
- if (inode->i_mode & S_ISGID)
- direntry->d_inode->i_gid =
- inode->i_gid;
- else
- direntry->d_inode->i_gid =
- current_fsgid();
- }
- }
- }
+ goto mkdir_out;
}
+
+ rc = cifs_mkdir_qinfo(inode, direntry, mode, full_path, cifs_sb, tcon,
+ xid);
mkdir_out:
/*
* Force revalidate to get parent dir info when needed since cached
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 03/45] CIFS: Separate protocol specific part from mkdir
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 01/45] CIFS: Make CAP_* checks protocol independent Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 02/45] CIFS: Simpliify cifs_mkdir call Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-4-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
` (42 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Pavel Shilovsky
From: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastry-7qunaywFIewox3rIn2DAYQ@public.gmane.org>
---
fs/cifs/cifsglob.h | 7 +++++++
fs/cifs/cifsproto.h | 4 +---
fs/cifs/cifssmb.c | 8 +++++---
fs/cifs/inode.c | 32 +++++++++++++-------------------
fs/cifs/smb1ops.c | 23 +++++++++++++++++++++++
5 files changed, 49 insertions(+), 25 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 5695693..1ae7531 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -246,6 +246,13 @@ struct smb_version_operations {
bool (*can_echo)(struct TCP_Server_Info *);
/* send echo request */
int (*echo)(struct TCP_Server_Info *);
+ /* create directory */
+ int (*mkdir)(const unsigned int, struct cifs_tcon *, const char *,
+ struct cifs_sb_info *);
+ /* set info on created directory */
+ void (*mkdir_setinfo)(struct inode *, const char *,
+ struct cifs_sb_info *, struct cifs_tcon *,
+ const unsigned int);
};
struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 51fbdf2..7e02362 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -295,9 +295,7 @@ extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
int remap);
extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
- const char *newName,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
+ const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, const struct nls_table *nls_codepage,
int remap_special_chars);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index ed472aa..d49eedf 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -992,14 +992,15 @@ RmDirRetry:
}
int
-CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, const struct nls_table *nls_codepage, int remap)
+CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb)
{
int rc = 0;
CREATE_DIRECTORY_REQ *pSMB = NULL;
CREATE_DIRECTORY_RSP *pSMBr = NULL;
int bytes_returned;
int name_len;
+ int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
cFYI(1, "In CIFSSMBMkDir");
MkDirRetry:
@@ -1010,7 +1011,8 @@ MkDirRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
- PATH_MAX, nls_codepage, remap);
+ PATH_MAX, cifs_sb->local_nls,
+ remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve check for buffer overruns BB */
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index e9ba1a1..d7e74b1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1272,24 +1272,11 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
+ struct TCP_Server_Info *server = tcon->ses->server;
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) &&
- (mode & S_IWUGO) == 0) {
- FILE_BASIC_INFO info;
- struct cifsInodeInfo *cifsInode;
- u32 dosattrs;
- int tmprc;
-
- memset(&info, 0, sizeof(info));
- cifsInode = CIFS_I(newinode);
- dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
- info.Attributes = cpu_to_le32(dosattrs);
- tmprc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (tmprc == 0)
- cifsInode->cifsAttrs = dosattrs;
- }
+ (mode & S_IWUGO) == 0 && server->ops->mkdir_setinfo)
+ server->ops->mkdir_setinfo(newinode, full_path, cifs_sb,
+ tcon, xid);
if (dentry->d_inode) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
dentry->d_inode->i_mode = (mode | S_IFDIR);
@@ -1377,6 +1364,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
char *full_path;
cFYI(1, "In cifs_mkdir, mode = 0x%hx inode = 0x%p", mode, inode);
@@ -1403,9 +1391,15 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, umode_t mode)
goto mkdir_out;
}
+ server = tcon->ses->server;
+
+ if (!server->ops->mkdir) {
+ rc = -ENOSYS;
+ goto mkdir_out;
+ }
+
/* BB add setting the equivalent of mode via CreateX w/ACLs */
- rc = CIFSSMBMkDir(xid, tcon, full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ rc = server->ops->mkdir(xid, tcon, full_path, cifs_sb);
if (rc) {
cFYI(1, "cifs_mkdir returned 0x%x", rc);
d_drop(direntry);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index c40356d..861e2df 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -586,6 +586,27 @@ cifs_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
#endif
}
+static void
+cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
+ struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+ const unsigned int xid)
+{
+ FILE_BASIC_INFO info;
+ struct cifsInodeInfo *cifsInode;
+ u32 dosattrs;
+ int rc;
+
+ memset(&info, 0, sizeof(info));
+ cifsInode = CIFS_I(inode);
+ dosattrs = cifsInode->cifsAttrs|ATTR_READONLY;
+ info.Attributes = cpu_to_le32(dosattrs);
+ rc = CIFSSMBSetPathInfo(xid, tcon, full_path, &info, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == 0)
+ cifsInode->cifsAttrs = dosattrs;
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -620,6 +641,8 @@ struct smb_version_operations smb1_operations = {
.get_srv_inum = cifs_get_srv_inum,
.build_path_to_root = cifs_build_path_to_root,
.echo = CIFSSMBEcho,
+ .mkdir = CIFSSMBMkDir,
+ .mkdir_setinfo = cifs_mkdir_setinfo,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (2 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 03/45] CIFS: Separate protocol specific part from mkdir Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-5-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 05/45] CIFS: Move rmdir code to ops struct Pavel Shilovsky
` (41 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA; +Cc: Pavel Shilovsky
From: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2inode.c | 30 ++++++++++++++++++++++++++++++
fs/cifs/smb2ops.c | 2 ++
fs/cifs/smb2proto.h | 6 ++++++
3 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1ba5c40..e129527 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -122,3 +122,33 @@ out:
kfree(smb2_data);
return rc;
}
+
+int
+smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb)
+{
+ return smb2_open_op_close(xid, tcon, cifs_sb, name,
+ FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
+ CREATE_NOT_FILE, NULL, SMB2_OP_MKDIR);
+}
+
+void
+smb2_mkdir_setinfo(struct inode *inode, const char *name,
+ struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon,
+ const unsigned int xid)
+{
+ FILE_BASIC_INFO data;
+ struct cifsInodeInfo *cifs_i;
+ u32 dosattrs;
+ int tmprc;
+
+ memset(&data, 0, sizeof(data));
+ cifs_i = CIFS_I(inode);
+ dosattrs = cifs_i->cifsAttrs | ATTR_READONLY;
+ data.Attributes = cpu_to_le32(dosattrs);
+ tmprc = smb2_open_op_close(xid, tcon, cifs_sb, name,
+ FILE_WRITE_ATTRIBUTES, FILE_CREATE, 0,
+ CREATE_NOT_FILE, &data, SMB2_OP_SET_INFO);
+ if (tmprc == 0)
+ cifs_i->cifsAttrs = dosattrs;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 410cf92..cc74871 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -318,6 +318,8 @@ struct smb_version_operations smb21_operations = {
.query_path_info = smb2_query_path_info,
.get_srv_inum = smb2_get_srv_inum,
.build_path_to_root = smb2_build_path_to_root,
+ .mkdir = smb2_mkdir,
+ .mkdir_setinfo = smb2_mkdir_setinfo,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 902bbe2..f992508 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -52,6 +52,12 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path, FILE_ALL_INFO *data,
bool *adjust_tz);
+extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb);
+extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
+ struct cifs_sb_info *cifs_sb,
+ struct cifs_tcon *tcon, const unsigned int xid);
+
/*
* SMB2 Worker functions - most of protocol specific implementation details
* are contained within these calls.
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 05/45] CIFS: Move rmdir code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (3 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 04/45] CIFS: Add SMB2 support for mkdir operation Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-6-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 06/45] CIFS: Add SMB2 support for rmdir Pavel Shilovsky
` (40 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 +++
fs/cifs/cifsproto.h | 3 +--
fs/cifs/cifssmb.c | 15 ++++++++-------
fs/cifs/inode.c | 15 +++++++++++----
fs/cifs/smb1ops.c | 1 +
5 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 1ae7531..a5b4e82 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -253,6 +253,9 @@ struct smb_version_operations {
void (*mkdir_setinfo)(struct inode *, const char *,
struct cifs_sb_info *, struct cifs_tcon *,
const unsigned int);
+ /* remove directory */
+ int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
+ struct cifs_sb_info *);
};
struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 7e02362..43784ee 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -297,8 +297,7 @@ extern int CIFSSMBUnixSetPathInfo(const unsigned int xid,
extern int CIFSSMBMkDir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name, const struct nls_table *nls_codepage,
- int remap_special_chars);
+ const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, __u16 type,
const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d49eedf..9fb21cd 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -948,15 +948,15 @@ DelFileRetry:
}
int
-CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon,
- const char *dirName, const struct nls_table *nls_codepage,
- int remap)
+CIFSSMBRmDir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb)
{
DELETE_DIRECTORY_REQ *pSMB = NULL;
DELETE_DIRECTORY_RSP *pSMBr = NULL;
int rc = 0;
int bytes_returned;
int name_len;
+ int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
cFYI(1, "In CIFSSMBRmDir");
RmDirRetry:
@@ -966,14 +966,15 @@ RmDirRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, dirName,
- PATH_MAX, nls_codepage, remap);
+ name_len = cifsConvertToUTF16((__le16 *) pSMB->DirName, name,
+ PATH_MAX, cifs_sb->local_nls,
+ remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve check for buffer overruns BB */
- name_len = strnlen(dirName, PATH_MAX);
+ name_len = strnlen(name, PATH_MAX);
name_len++; /* trailing null */
- strncpy(pSMB->DirName, dirName, name_len);
+ strncpy(pSMB->DirName, name, name_len);
}
pSMB->BufferFormat = 0x04;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index d7e74b1..7354877 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1426,7 +1426,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
unsigned int xid;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
char *full_path = NULL;
struct cifsInodeInfo *cifsInode;
@@ -1446,10 +1447,16 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
rc = PTR_ERR(tlink);
goto rmdir_exit;
}
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ if (!server->ops->rmdir) {
+ rc = -ENOSYS;
+ cifs_put_tlink(tlink);
+ goto rmdir_exit;
+ }
- rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
cifs_put_tlink(tlink);
if (!rc) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 861e2df..3129ac7 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -643,6 +643,7 @@ struct smb_version_operations smb1_operations = {
.echo = CIFSSMBEcho,
.mkdir = CIFSSMBMkDir,
.mkdir_setinfo = cifs_mkdir_setinfo,
+ .rmdir = CIFSSMBRmDir,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 06/45] CIFS: Add SMB2 support for rmdir
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (4 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 05/45] CIFS: Move rmdir code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-7-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 07/45] CIFS: Protect i_nlink from being negative Pavel Shilovsky
` (39 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2inode.c | 9 +++++++++
fs/cifs/smb2ops.c | 1 +
fs/cifs/smb2proto.h | 2 ++
3 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index e129527..2aa5cb0 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -152,3 +152,12 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
if (tmprc == 0)
cifs_i->cifsAttrs = dosattrs;
}
+
+int
+smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb)
+{
+ return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+ 0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
+ NULL, SMB2_OP_DELETE);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index cc74871..826209b 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -320,6 +320,7 @@ struct smb_version_operations smb21_operations = {
.build_path_to_root = smb2_build_path_to_root,
.mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo,
+ .rmdir = smb2_rmdir,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f992508..bfaa7b1 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -57,6 +57,8 @@ extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon, const unsigned int xid);
+extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb);
/*
* SMB2 Worker functions - most of protocol specific implementation details
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 07/45] CIFS: Protect i_nlink from being negative
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (5 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 06/45] CIFS: Add SMB2 support for rmdir Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-8-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 08/45] CIFS: Move unlink code to ops struct Pavel Shilovsky
` (38 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
that can cause warning messages.
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/inode.c | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7354877..88afb1a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1110,6 +1110,15 @@ undo_setattr:
goto out_close;
}
+/* copied from fs/nfs/dir.c with small changes */
+static void
+cifs_drop_nlink(struct inode *inode)
+{
+ spin_lock(&inode->i_lock);
+ if (inode->i_nlink > 0)
+ drop_nlink(inode);
+ spin_unlock(&inode->i_lock);
+}
/*
* If dentry->d_inode is null (usually meaning the cached dentry
@@ -1166,13 +1175,13 @@ retry_std_delete:
psx_del_no_retry:
if (!rc) {
if (inode)
- drop_nlink(inode);
+ cifs_drop_nlink(inode);
} else if (rc == -ENOENT) {
d_drop(dentry);
} else if (rc == -ETXTBSY) {
rc = cifs_rename_pending_delete(full_path, dentry, xid);
if (rc == 0)
- drop_nlink(inode);
+ cifs_drop_nlink(inode);
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
if (attrs == NULL) {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 08/45] CIFS: Move unlink code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (6 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 07/45] CIFS: Protect i_nlink from being negative Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-9-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 09/45] CIFS: Add SMB2 support for unlink Pavel Shilovsky
` (37 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 6 ++++++
fs/cifs/cifsproto.h | 9 ++++++---
fs/cifs/cifssmb.c | 16 ++++++++--------
fs/cifs/inode.c | 32 +++++++++++++++++++++-----------
fs/cifs/smb1ops.c | 2 ++
5 files changed, 43 insertions(+), 22 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a5b4e82..bd53d97 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -256,6 +256,12 @@ struct smb_version_operations {
/* remove directory */
int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
struct cifs_sb_info *);
+ /* unlink file */
+ int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
+ struct cifs_sb_info *);
+ /* open, rename and delete file */
+ int (*rename_pending_delete)(const char *, struct dentry *,
+ const unsigned int);
};
struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 43784ee..e9349af 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -144,6 +144,11 @@ extern int cifs_get_file_info_unix(struct file *filp);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, unsigned int xid);
+extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
+ unsigned int xid, char *full_path, __u32 dosattr);
+extern int cifs_rename_pending_delete(const char *full_path,
+ struct dentry *dentry,
+ const unsigned int xid);
extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_fattr *fattr, struct inode *inode,
const char *path, const __u16 *pfid);
@@ -303,9 +308,7 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
- const char *name,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
+ const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
const char *fromName, const char *toName,
const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 9fb21cd..395f3e2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -902,15 +902,15 @@ PsxDelete:
}
int
-CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, const struct nls_table *nls_codepage,
- int remap)
+CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb)
{
DELETE_FILE_REQ *pSMB = NULL;
DELETE_FILE_RSP *pSMBr = NULL;
int rc = 0;
int bytes_returned;
int name_len;
+ int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
DelFileRetry:
rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -919,15 +919,15 @@ DelFileRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
- PATH_MAX, nls_codepage, remap);
+ name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
+ PATH_MAX, cifs_sb->local_nls,
+ remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
+ name_len = strnlen(name, PATH_MAX);
name_len++; /* trailing null */
- strncpy(pSMB->fileName, fileName, name_len);
+ strncpy(pSMB->fileName, name, name_len);
}
pSMB->SearchAttributes =
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 88afb1a..9685eb1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -878,9 +878,9 @@ out:
return inode;
}
-static int
+int
cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
- char *full_path, __u32 dosattr)
+ char *full_path, __u32 dosattr)
{
int rc;
int oplock = 0;
@@ -995,13 +995,13 @@ out:
}
/*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
* and rename it to a random name that hopefully won't conflict with
* anything else.
*/
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
- unsigned int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+ const unsigned int xid)
{
int oplock = 0;
int rc;
@@ -1138,6 +1138,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct iattr *attrs = NULL;
__u32 dosattr = 0, origattr = 0;
@@ -1147,6 +1148,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
if (IS_ERR(tlink))
return PTR_ERR(tlink);
tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
xid = get_xid();
@@ -1169,8 +1171,12 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
}
retry_std_delete:
- rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (!server->ops->unlink) {
+ rc = -ENOSYS;
+ goto psx_del_no_retry;
+ }
+
+ rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
psx_del_no_retry:
if (!rc) {
@@ -1179,9 +1185,13 @@ psx_del_no_retry:
} else if (rc == -ENOENT) {
d_drop(dentry);
} else if (rc == -ETXTBSY) {
- rc = cifs_rename_pending_delete(full_path, dentry, xid);
- if (rc == 0)
- cifs_drop_nlink(inode);
+ if (server->ops->rename_pending_delete) {
+ rc = server->ops->rename_pending_delete(full_path,
+ dentry, xid);
+ if (rc == 0)
+ cifs_drop_nlink(inode);
+ } else
+ rc = -ENOSYS;
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
if (attrs == NULL) {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3129ac7..725fa61 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -644,6 +644,8 @@ struct smb_version_operations smb1_operations = {
.mkdir = CIFSSMBMkDir,
.mkdir_setinfo = cifs_mkdir_setinfo,
.rmdir = CIFSSMBRmDir,
+ .unlink = CIFSSMBDelFile,
+ .rename_pending_delete = cifs_rename_pending_delete,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 09/45] CIFS: Add SMB2 support for unlink
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (7 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 08/45] CIFS: Move unlink code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-10-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo Pavel Shilovsky
` (36 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2inode.c | 9 +++++++++
fs/cifs/smb2ops.c | 1 +
fs/cifs/smb2proto.h | 2 ++
3 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 2aa5cb0..02a9bda 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -161,3 +161,12 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
NULL, SMB2_OP_DELETE);
}
+
+int
+smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+ struct cifs_sb_info *cifs_sb)
+{
+ return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+ 0, CREATE_DELETE_ON_CLOSE, NULL,
+ SMB2_OP_DELETE);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 826209b..bf9b318 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -321,6 +321,7 @@ struct smb_version_operations smb21_operations = {
.mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo,
.rmdir = smb2_rmdir,
+ .unlink = smb2_unlink,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index bfaa7b1..f4ac727 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -59,6 +59,8 @@ extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
struct cifs_tcon *tcon, const unsigned int xid);
extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *name, struct cifs_sb_info *cifs_sb);
/*
* SMB2 Worker functions - most of protocol specific implementation details
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (8 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 09/45] CIFS: Add SMB2 support for unlink Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-11-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 11/45] CIFS: Move open code to ops struct Pavel Shilovsky
` (35 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
This is help us to extend the code for future protocols that can use
another fid mechanism (as SMB2 that has it divided into two parts:
persistent and violatile).
Also rename variables and refactor the code around the changes.
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsacl.c | 2 +-
fs/cifs/cifsglob.h | 6 ++-
fs/cifs/cifssmb.c | 4 +-
fs/cifs/file.c | 116 ++++++++++++++++++++++++++--------------------------
fs/cifs/inode.c | 10 ++--
fs/cifs/ioctl.c | 13 ++++--
fs/cifs/misc.c | 2 +-
fs/cifs/readdir.c | 10 ++--
fs/cifs/smb1ops.c | 2 +-
9 files changed, 87 insertions(+), 78 deletions(-)
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index f8c8464..d98a7c3 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1222,7 +1222,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
- pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
+ pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
cifsFileInfo_put(open_file);
return pntsd;
}
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index bd53d97..01ee8d2 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -746,6 +746,10 @@ struct cifs_search_info {
bool smallBuf:1; /* so we know which buf_release function to call */
};
+struct cifs_fid {
+ __u16 netfid;
+};
+
struct cifsFileInfo {
struct list_head tlist; /* pointer to next fid owned by tcon */
struct list_head flist; /* next fid (file instance) for this inode */
@@ -755,7 +759,7 @@ struct cifsFileInfo {
*/
unsigned int uid; /* allows finding which FileInfo structure */
__u32 pid; /* process id who opened file */
- __u16 netfid; /* file id from remote */
+ struct cifs_fid fid; /* file id from remote */
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
struct dentry *dentry;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 395f3e2..2936875 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1627,7 +1627,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
smb->AndXCommand = 0xFF; /* none */
- smb->Fid = rdata->cfile->netfid;
+ smb->Fid = rdata->cfile->fid.netfid;
smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
if (wct == 12)
smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
@@ -2079,7 +2079,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
smb->AndXCommand = 0xFF; /* none */
- smb->Fid = wdata->cfile->netfid;
+ smb->Fid = wdata->cfile->fid.netfid;
smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
if (wct == 14)
smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 1712794..f542574 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -247,39 +247,39 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
- struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
- struct cifsFileInfo *pCifsFile;
-
- pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
- if (pCifsFile == NULL)
- return pCifsFile;
-
- pCifsFile->count = 1;
- pCifsFile->netfid = fileHandle;
- pCifsFile->pid = current->tgid;
- pCifsFile->uid = current_fsuid();
- pCifsFile->dentry = dget(dentry);
- pCifsFile->f_flags = file->f_flags;
- pCifsFile->invalidHandle = false;
- pCifsFile->tlink = cifs_get_tlink(tlink);
- mutex_init(&pCifsFile->fh_mutex);
- INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
- INIT_LIST_HEAD(&pCifsFile->llist);
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
+ struct cifsFileInfo *cfile;
+
+ cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+ if (cfile == NULL)
+ return cfile;
+
+ cfile->count = 1;
+ cfile->fid.netfid = fileHandle;
+ cfile->pid = current->tgid;
+ cfile->uid = current_fsuid();
+ cfile->dentry = dget(dentry);
+ cfile->f_flags = file->f_flags;
+ cfile->invalidHandle = false;
+ cfile->tlink = cifs_get_tlink(tlink);
+ mutex_init(&cfile->fh_mutex);
+ INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
+ INIT_LIST_HEAD(&cfile->llist);
spin_lock(&cifs_file_list_lock);
- list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
+ list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
/* if readable file instance put first in list*/
if (file->f_mode & FMODE_READ)
- list_add(&pCifsFile->flist, &pCifsInode->openFileList);
+ list_add(&cfile->flist, &cinode->openFileList);
else
- list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
+ list_add_tail(&cfile->flist, &cinode->openFileList);
spin_unlock(&cifs_file_list_lock);
- cifs_set_oplock_level(pCifsInode, oplock);
- pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
+ cifs_set_oplock_level(cinode, oplock);
+ cinode->can_cache_brlcks = cinode->clientCanCacheAll;
- file->private_data = pCifsFile;
- return pCifsFile;
+ file->private_data = cfile;
+ return cfile;
}
static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
@@ -327,7 +327,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
unsigned int xid;
int rc;
xid = get_xid();
- rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
+ rc = CIFSSMBClose(xid, tcon, cifs_file->fid.netfid);
free_xid(xid);
}
@@ -552,7 +552,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
}
reopen_success:
- pCifsFile->netfid = netfid;
+ pCifsFile->fid.netfid = netfid;
pCifsFile->invalidHandle = false;
mutex_unlock(&pCifsFile->fh_mutex);
pCifsInode = CIFS_I(inode);
@@ -600,39 +600,37 @@ int cifs_closedir(struct inode *inode, struct file *file)
{
int rc = 0;
unsigned int xid;
- struct cifsFileInfo *pCFileStruct = file->private_data;
- char *ptmp;
+ struct cifsFileInfo *cfile = file->private_data;
+ char *tmp;
cFYI(1, "Closedir inode = 0x%p", inode);
xid = get_xid();
- if (pCFileStruct) {
- struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
+ if (cfile) {
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
cFYI(1, "Freeing private data in close dir");
spin_lock(&cifs_file_list_lock);
- if (!pCFileStruct->srch_inf.endOfSearch &&
- !pCFileStruct->invalidHandle) {
- pCFileStruct->invalidHandle = true;
+ if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+ cfile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock);
- rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
- cFYI(1, "Closing uncompleted readdir with rc %d",
- rc);
+ rc = CIFSFindClose(xid, tcon, cfile->fid.netfid);
+ cFYI(1, "Closing uncompleted readdir with rc %d", rc);
/* not much we can do if it fails anyway, ignore rc */
rc = 0;
} else
spin_unlock(&cifs_file_list_lock);
- ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
- if (ptmp) {
+ tmp = cfile->srch_inf.ntwrk_buf_start;
+ if (tmp) {
cFYI(1, "closedir free smb buf in srch struct");
- pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
- if (pCFileStruct->srch_inf.smallBuf)
- cifs_small_buf_release(ptmp);
+ cfile->srch_inf.ntwrk_buf_start = NULL;
+ if (cfile->srch_inf.smallBuf)
+ cifs_small_buf_release(tmp);
else
- cifs_buf_release(ptmp);
+ cifs_buf_release(tmp);
}
- cifs_put_tlink(pCFileStruct->tlink);
+ cifs_put_tlink(cfile->tlink);
kfree(file->private_data);
file->private_data = NULL;
}
@@ -923,7 +921,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
cur->OffsetLow = cpu_to_le32((u32)li->offset);
cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
if (++num == max_num) {
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ stored_rc = cifs_lockv(xid, tcon,
+ cfile->fid.netfid,
(__u8)li->type, 0, num,
buf);
if (stored_rc)
@@ -935,7 +934,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
}
if (num) {
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
(__u8)types[i], 0, num, buf);
if (stored_rc)
rc = stored_rc;
@@ -1029,7 +1028,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
type = CIFS_WRLCK;
lck = list_entry(el, struct lock_to_push, llist);
lck->pid = flock->fl_pid;
- lck->netfid = cfile->netfid;
+ lck->netfid = cfile->fid.netfid;
lck->length = length;
lck->type = type;
lck->offset = flock->fl_start;
@@ -1130,7 +1129,7 @@ static int
cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
__u64 length, __u32 type, int lock, int unlock, bool wait)
{
- return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
+ return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
current->tgid, length, offset, unlock, lock,
(__u8)type, wait, 0);
}
@@ -1144,7 +1143,7 @@ cifs_getlk(struct file *file, struct file_lock *flock, __u32 type,
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
- __u16 netfid = cfile->netfid;
+ __u16 netfid = cfile->fid.netfid;
if (posix_lck) {
int posix_lock_type;
@@ -1288,7 +1287,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
*/
list_move(&li->llist, &tmp_llist);
if (++num == max_num) {
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ stored_rc = cifs_lockv(xid, tcon,
+ cfile->fid.netfid,
li->type, num, 0, buf);
if (stored_rc) {
/*
@@ -1311,7 +1311,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
cur++;
}
if (num) {
- stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+ stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
types[i], num, 0, buf);
if (stored_rc) {
cifs_move_llist(&tmp_llist, &cfile->llist);
@@ -1336,7 +1336,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
struct cifsFileInfo *cfile = (struct cifsFileInfo *)file->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
struct TCP_Server_Info *server = tcon->ses->server;
- __u16 netfid = cfile->netfid;
+ __u16 netfid = cfile->fid.netfid;
if (posix_lck) {
int posix_lock_type;
@@ -1416,7 +1416,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
tcon->ses->server);
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- netfid = cfile->netfid;
+ netfid = cfile->fid.netfid;
cinode = CIFS_I(file->f_path.dentry->d_inode);
if (cap_unix(tcon->ses) &&
@@ -1507,7 +1507,7 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
/* iov[0] is reserved for smb header */
iov[1].iov_base = (char *)write_data + total_written;
iov[1].iov_len = len;
- io_parms.netfid = open_file->netfid;
+ io_parms.netfid = open_file->fid.netfid;
io_parms.pid = pid;
io_parms.tcon = pTcon;
io_parms.offset = *poffset;
@@ -2071,7 +2071,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
tcon = tlink_tcon(smbfile->tlink);
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
- rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+ rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
free_xid(xid);
mutex_unlock(&inode->i_mutex);
@@ -2099,7 +2099,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
tcon = tlink_tcon(smbfile->tlink);
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
- rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+ rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
free_xid(xid);
mutex_unlock(&inode->i_mutex);
@@ -2795,7 +2795,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
if (rc != 0)
break;
}
- io_parms.netfid = open_file->netfid;
+ io_parms.netfid = open_file->fid.netfid;
io_parms.pid = pid;
io_parms.tcon = tcon;
io_parms.offset = *poffset;
@@ -3369,7 +3369,7 @@ void cifs_oplock_break(struct work_struct *work)
* disconnected since oplock already released by the server
*/
if (!cfile->oplock_break_cancelled) {
- rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
+ rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->fid.netfid,
current->tgid, 0, 0, 0, 0,
LOCKING_ANDX_OPLOCK_RELEASE, false,
cinode->clientCanCacheRead ? 1 : 0);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 9685eb1..1eeb6a0 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -298,7 +298,7 @@ int cifs_get_file_info_unix(struct file *filp)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
xid = get_xid();
- rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+ rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
if (!rc) {
cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
} else if (rc == -EREMOTE) {
@@ -566,7 +566,7 @@ int cifs_get_file_info(struct file *filp)
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
xid = get_xid();
- rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+ rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
switch (rc) {
case 0:
cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
@@ -932,7 +932,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
*/
open_file = find_writable_file(cifsInode, true);
if (open_file) {
- netfid = open_file->netfid;
+ netfid = open_file->fid.netfid;
netpid = open_file->pid;
pTcon = tlink_tcon(open_file->tlink);
goto set_via_filehandle;
@@ -1887,7 +1887,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
*/
open_file = find_writable_file(cifsInode, true);
if (open_file) {
- __u16 nfid = open_file->netfid;
+ __u16 nfid = open_file->fid.netfid;
__u32 npid = open_file->pid;
pTcon = tlink_tcon(open_file->tlink);
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
@@ -2061,7 +2061,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
args->device = 0;
open_file = find_writable_file(cifsInode, true);
if (open_file) {
- u16 nfid = open_file->netfid;
+ u16 nfid = open_file->fid.netfid;
u32 npid = open_file->pid;
pTcon = tlink_tcon(open_file->tlink);
rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index ae082a6..5b3481b 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -75,8 +75,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
tcon = tlink_tcon(pSMBFile->tlink);
caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
if (CIFS_UNIX_EXTATTR_CAP & caps) {
- rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
- &ExtAttrBits, &ExtAttrMask);
+ rc = CIFSGetExtAttr(xid, tcon,
+ pSMBFile->fid.netfid,
+ &ExtAttrBits, &ExtAttrMask);
if (rc == 0)
rc = put_user(ExtAttrBits &
FS_FL_USER_VISIBLE,
@@ -94,8 +95,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
rc = -EFAULT;
break;
}
- /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
- extAttrBits, &ExtAttrMask);*/
+ /*
+ * rc = CIFSGetExtAttr(xid, tcon,
+ * pSMBFile->fid.netfid,
+ * extAttrBits,
+ * &ExtAttrMask);
+ */
}
cFYI(1, "set flags not implemented yet");
break;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index ce41fee..a921b07 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -466,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
list_for_each(tmp2, &tcon->openFileList) {
netfile = list_entry(tmp2, struct cifsFileInfo,
tlist);
- if (pSMB->Fid != netfile->netfid)
+ if (pSMB->Fid != netfile->fid.netfid)
continue;
cFYI(1, "file id match, oplock break");
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index d87f826..9e76e3b 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -279,7 +279,7 @@ ffirst_retry:
search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
- &cifsFile->netfid, search_flags, &cifsFile->srch_inf,
+ &cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
if (rc == 0)
@@ -545,7 +545,7 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
!cifsFile->invalidHandle) {
cifsFile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock);
- CIFSFindClose(xid, pTcon, cifsFile->netfid);
+ CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
} else
spin_unlock(&cifs_file_list_lock);
if (cifsFile->srch_inf.ntwrk_buf_start) {
@@ -577,8 +577,8 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
(rc == 0) && !cifsFile->srch_inf.endOfSearch) {
cFYI(1, "calling findnext2");
- rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags,
- &cifsFile->srch_inf);
+ rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid,
+ search_flags, &cifsFile->srch_inf);
/* FindFirst/Next set last_entry to NULL on malformed reply */
if (cifsFile->srch_inf.last_entry)
cifs_save_resume_key(cifsFile->srch_inf.last_entry,
@@ -781,7 +781,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
}
} /* else {
cifsFile->invalidHandle = true;
- CIFSFindClose(xid, pTcon, cifsFile->netfid);
+ CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
} */
pTcon = tlink_tcon(cifsFile->tlink);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 725fa61..b170da0 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -63,7 +63,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
static bool
cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
{
- return ob1->netfid == ob2->netfid;
+ return ob1->fid.netfid == ob2->fid.netfid;
}
static unsigned int
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 11/45] CIFS: Move open code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (9 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 10/45] CIFS: Replace netfid with cifs_fid struct in cifsFileInfo Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-12-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 12/45] CIFS: Move close " Pavel Shilovsky
` (34 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 7 +++++
fs/cifs/cifsproto.h | 7 +++--
fs/cifs/dir.c | 17 +++++++------
fs/cifs/file.c | 63 ++++++++++++++++++++++++--------------------------
fs/cifs/smb1ops.c | 29 +++++++++++++++++++++++
5 files changed, 79 insertions(+), 44 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 01ee8d2..c4375d8 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -171,6 +171,7 @@ struct cifs_tcon;
struct dfs_info3_param;
struct cifs_fattr;
struct smb_vol;
+struct cifs_fid;
struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -262,6 +263,12 @@ struct smb_version_operations {
/* open, rename and delete file */
int (*rename_pending_delete)(const char *, struct dentry *,
const unsigned int);
+ /* open a file for non-posix mounts */
+ int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
+ int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
+ struct cifs_sb_info *);
+ /* set fid protocol-specific info */
+ void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
};
struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index e9349af..80b0e40 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -121,9 +121,10 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
int offset);
extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
-extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
- struct file *file, struct tcon_link *tlink,
- __u32 oplock);
+extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
+ struct file *file,
+ struct tcon_link *tlink,
+ __u32 oplock);
extern int cifs_posix_open(char *full_path, struct inode **inode,
struct super_block *sb, int mode,
unsigned int f_flags, __u32 *oplock, __u16 *netfid,
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index cbe709a..eebffaf 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -384,11 +384,12 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
unsigned int xid;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
- __u16 fileHandle;
+ struct cifs_fid fid;
__u32 oplock;
- struct cifsFileInfo *pfile_info;
+ struct cifsFileInfo *file_info;
- /* Posix open is only called (at lookup time) for file create now. For
+ /*
+ * 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
* or directory yet, and current Samba no longer allows us to do posix
* open on dirs, we could end up wasting an open call on what turns out
@@ -422,20 +423,20 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
tcon = tlink_tcon(tlink);
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fileHandle, opened);
+ &oplock, &fid.netfid, opened);
if (rc)
goto out;
rc = finish_open(file, direntry, generic_file_open, opened);
if (rc) {
- CIFSSMBClose(xid, tcon, fileHandle);
+ CIFSSMBClose(xid, tcon, fid.netfid);
goto out;
}
- pfile_info = cifs_new_fileinfo(fileHandle, file, tlink, oplock);
- if (pfile_info == NULL) {
- CIFSSMBClose(xid, tcon, fileHandle);
+ file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
+ if (file_info == NULL) {
+ CIFSSMBClose(xid, tcon, fid.netfid);
rc = -ENOMEM;
}
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f542574..3f4b4ba 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -169,16 +169,19 @@ posix_open_ret:
static int
cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
- struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
- __u16 *pnetfid, unsigned int xid)
+ struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
+ struct cifs_fid *fid, unsigned int xid)
{
int rc;
- int desiredAccess;
+ int desired_access;
int disposition;
int create_options = CREATE_NOT_DIR;
FILE_ALL_INFO *buf;
- desiredAccess = cifs_convert_flags(f_flags);
+ if (!tcon->ses->server->ops->open)
+ return -ENOSYS;
+
+ desired_access = cifs_convert_flags(f_flags);
/*********************************************************************
* open flag mapping table:
@@ -215,16 +218,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
- if (tcon->ses->capabilities & CAP_NT_SMBS)
- rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
- desiredAccess, create_options, pnetfid, poplock, buf,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
- & CIFS_MOUNT_MAP_SPECIAL_CHR);
- else
- rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
- desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
- & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ rc = tcon->ses->server->ops->open(xid, tcon, full_path, disposition,
+ desired_access, create_options, fid,
+ oplock, buf, cifs_sb);
if (rc)
goto out;
@@ -234,7 +230,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
xid);
else
rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
- xid, pnetfid);
+ xid, &fid->netfid);
out:
kfree(buf);
@@ -242,7 +238,7 @@ out:
}
struct cifsFileInfo *
-cifs_new_fileinfo(__u16 fileHandle, struct file *file,
+cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
struct tcon_link *tlink, __u32 oplock)
{
struct dentry *dentry = file->f_path.dentry;
@@ -255,7 +251,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
return cfile;
cfile->count = 1;
- cfile->fid.netfid = fileHandle;
cfile->pid = current->tgid;
cfile->uid = current_fsuid();
cfile->dentry = dget(dentry);
@@ -265,6 +260,7 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
mutex_init(&cfile->fh_mutex);
INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
INIT_LIST_HEAD(&cfile->llist);
+ tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
spin_lock(&cifs_file_list_lock);
list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
@@ -275,9 +271,6 @@ cifs_new_fileinfo(__u16 fileHandle, struct file *file,
list_add_tail(&cfile->flist, &cinode->openFileList);
spin_unlock(&cifs_file_list_lock);
- cifs_set_oplock_level(cinode, oplock);
- cinode->can_cache_brlcks = cinode->clientCanCacheAll;
-
file->private_data = cfile;
return cfile;
}
@@ -355,10 +348,10 @@ int cifs_open(struct inode *inode, struct file *file)
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
struct tcon_link *tlink;
- struct cifsFileInfo *pCifsFile = NULL;
+ struct cifsFileInfo *cfile = NULL;
char *full_path = NULL;
bool posix_open_ok = false;
- __u16 netfid;
+ struct cifs_fid fid;
xid = get_xid();
@@ -390,7 +383,7 @@ int cifs_open(struct inode *inode, struct file *file)
/* can not refresh inode info since size could be stale */
rc = cifs_posix_open(full_path, &inode, inode->i_sb,
cifs_sb->mnt_file_mode /* ignored */,
- file->f_flags, &oplock, &netfid, xid);
+ file->f_flags, &oplock, &fid.netfid, xid);
if (rc == 0) {
cFYI(1, "posix open succeeded");
posix_open_ok = true;
@@ -406,20 +399,22 @@ int cifs_open(struct inode *inode, struct file *file)
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
(rc != -EOPNOTSUPP)) /* path not found or net err */
goto out;
- /* else fallthrough to retry open the old way on network i/o
- or DFS errors */
+ /*
+ * Else fallthrough to retry open the old way on network i/o
+ * or DFS errors.
+ */
}
if (!posix_open_ok) {
rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
- file->f_flags, &oplock, &netfid, xid);
+ file->f_flags, &oplock, &fid, xid);
if (rc)
goto out;
}
- pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
- if (pCifsFile == NULL) {
- CIFSSMBClose(xid, tcon, netfid);
+ cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
+ if (cfile == NULL) {
+ CIFSSMBClose(xid, tcon, fid.netfid);
rc = -ENOMEM;
goto out;
}
@@ -427,8 +422,10 @@ int cifs_open(struct inode *inode, struct file *file)
cifs_fscache_set_inode_cookie(inode, file);
if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
- /* time to set mode which we can not set earlier due to
- problems creating new read-only files */
+ /*
+ * Time to set mode which we can not set earlier due to
+ * problems creating new read-only files.
+ */
struct cifs_unix_set_info_args args = {
.mode = inode->i_mode,
.uid = NO_CHANGE_64,
@@ -438,8 +435,8 @@ int cifs_open(struct inode *inode, struct file *file)
.mtime = NO_CHANGE_64,
.device = 0,
};
- CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
- pCifsFile->pid);
+ CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
+ cfile->pid);
}
out:
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index b170da0..907b308 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -607,6 +607,33 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
cifsInode->cifsAttrs = dosattrs;
}
+static int
+cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+ int disposition, int desired_access, int create_options,
+ struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+ struct cifs_sb_info *cifs_sb)
+{
+ if (!(tcon->ses->capabilities & CAP_NT_SMBS))
+ return SMBLegacyOpen(xid, tcon, path, disposition,
+ desired_access, CREATE_NOT_DIR,
+ &fid->netfid, oplock, buf,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+ & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ return CIFSSMBOpen(xid, tcon, path, disposition, desired_access,
+ create_options, &fid->netfid, oplock, buf,
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+}
+
+static void
+cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+ struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+ cfile->fid.netfid = fid->netfid;
+ cifs_set_oplock_level(cinode, oplock);
+ cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -646,6 +673,8 @@ struct smb_version_operations smb1_operations = {
.rmdir = CIFSSMBRmDir,
.unlink = CIFSSMBDelFile,
.rename_pending_delete = cifs_rename_pending_delete,
+ .open = cifs_open_file,
+ .set_fid = cifs_set_fid,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 12/45] CIFS: Move close code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (10 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 11/45] CIFS: Move open code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-13-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 13/45] CIFS: Add open/close file support for SMB2 Pavel Shilovsky
` (33 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 2 ++
fs/cifs/file.c | 10 +++++++---
fs/cifs/smb1ops.c | 8 ++++++++
3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c4375d8..b3cbce6 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -269,6 +269,8 @@ struct smb_version_operations {
struct cifs_sb_info *);
/* set fid protocol-specific info */
void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
+ /* close a file */
+ int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
};
struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 3f4b4ba..b18b36a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -317,10 +317,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
cancel_work_sync(&cifs_file->oplock_break);
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
+ struct TCP_Server_Info *server = tcon->ses->server;
unsigned int xid;
- int rc;
+ int rc = -ENOSYS;
+
xid = get_xid();
- rc = CIFSSMBClose(xid, tcon, cifs_file->fid.netfid);
+ if (server->ops->close)
+ rc = server->ops->close(xid, tcon, &cifs_file->fid);
free_xid(xid);
}
@@ -414,7 +417,8 @@ int cifs_open(struct inode *inode, struct file *file)
cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
if (cfile == NULL) {
- CIFSSMBClose(xid, tcon, fid.netfid);
+ if (tcon->ses->server->ops->close)
+ tcon->ses->server->ops->close(xid, tcon, &fid);
rc = -ENOMEM;
goto out;
}
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 907b308..bb75847 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -634,6 +634,13 @@ cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
cinode->can_cache_brlcks = cinode->clientCanCacheAll;
}
+static int
+cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid)
+{
+ return CIFSSMBClose(xid, tcon, fid->netfid);
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -675,6 +682,7 @@ struct smb_version_operations smb1_operations = {
.rename_pending_delete = cifs_rename_pending_delete,
.open = cifs_open_file,
.set_fid = cifs_set_fid,
+ .close = cifs_close_file,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 13/45] CIFS: Add open/close file support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (11 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 12/45] CIFS: Move close " Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 14/45] CIFS: Move guery file info code to ops struct Pavel Shilovsky
` (32 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/Makefile | 2 +-
fs/cifs/cifsglob.h | 4 ++
fs/cifs/smb2file.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2inode.c | 4 +-
fs/cifs/smb2ops.c | 22 ++++++++++++-
fs/cifs/smb2pdu.c | 53 ++++++++++++++++++++++++-------
fs/cifs/smb2pdu.h | 4 ++
fs/cifs/smb2proto.h | 14 ++++++++-
8 files changed, 172 insertions(+), 17 deletions(-)
create mode 100644 fs/cifs/smb2file.c
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index feee943..aa0d68b 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -17,4 +17,4 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o \
- smb2misc.o smb2pdu.o smb2inode.o
+ smb2misc.o smb2pdu.o smb2inode.o smb2file.o
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b3cbce6..bd2b397 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -757,6 +757,10 @@ struct cifs_search_info {
struct cifs_fid {
__u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+ __u64 persistent_fid; /* persist file id for smb2 */
+ __u64 volatile_fid; /* volatile file id for smb2 */
+#endif
};
struct cifsFileInfo {
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
new file mode 100644
index 0000000..a7618df
--- /dev/null
+++ b/fs/cifs/smb2file.c
@@ -0,0 +1,86 @@
+/*
+ * fs/cifs/smb2file.c
+ *
+ * Copyright (C) International Business Machines Corp., 2002, 2011
+ * Author(s): Steve French (sfrench-r/Jw6+rmf7HQT0dZR+AlfA@public.gmane.org),
+ * Pavel Shilovsky ((pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org) 2012
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
+#include "fscache.h"
+#include "smb2proto.h"
+
+int
+smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+ int disposition, int desired_access, int create_options,
+ struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+ struct cifs_sb_info *cifs_sb)
+{
+ int rc;
+ __le16 *smb2_path;
+ struct smb2_file_all_info *smb2_data = NULL;
+
+ smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (smb2_path == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+ GFP_KERNEL);
+ if (smb2_data == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ desired_access |= FILE_READ_ATTRIBUTES;
+
+ rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
+ &fid->volatile_fid, desired_access, disposition,
+ 0, 0, smb2_data);
+ if (rc)
+ goto out;
+
+ if (buf) {
+ /* open response does not have IndexNumber field - get it */
+ rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
+ fid->volatile_fid,
+ &smb2_data->IndexNumber);
+ if (rc) {
+ /* let get_inode_info disable server inode numbers */
+ smb2_data->IndexNumber = 0;
+ rc = 0;
+ }
+ move_smb2_info_to_cifs(buf, smb2_data);
+ }
+
+out:
+ *oplock = 0;
+ kfree(smb2_data);
+ kfree(smb2_path);
+ return rc;
+}
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 02a9bda..ee3a1ef 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -54,7 +54,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
desired_access, create_disposition, file_attributes,
- create_options);
+ create_options, NULL);
if (rc) {
kfree(utf16_path);
return rc;
@@ -86,7 +86,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
-static void
+void
move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
{
memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index bf9b318..eba12b3 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -170,7 +170,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
return -ENOMEM;
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
- FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
+ FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
if (rc) {
kfree(utf16_path);
return rc;
@@ -292,6 +292,23 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
#endif
}
+static void
+smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+ /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
+ cfile->fid.persistent_fid = fid->persistent_fid;
+ cfile->fid.volatile_fid = fid->volatile_fid;
+ /* cifs_set_oplock_level(cinode, oplock); */
+ /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
+}
+
+static int
+smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid)
+{
+ return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -322,6 +339,9 @@ struct smb_version_operations smb21_operations = {
.mkdir_setinfo = smb2_mkdir_setinfo,
.rmdir = smb2_rmdir,
.unlink = smb2_unlink,
+ .open = smb2_open_file,
+ .set_fid = smb2_set_fid,
+ .close = smb2_close_file,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 62b3f17..231e970 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -833,7 +833,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
int
SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
- __u32 create_disposition, __u32 file_attributes, __u32 create_options)
+ __u32 create_disposition, __u32 file_attributes, __u32 create_options,
+ struct smb2_file_all_info *buf)
{
struct smb2_create_req *req;
struct smb2_create_rsp *rsp;
@@ -856,9 +857,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
if (rc)
return rc;
- if (enable_oplocks)
+ /* if (server->oplocks)
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
- else
+ else */
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
req->ImpersonationLevel = IL_IMPERSONATION;
req->DesiredAccess = cpu_to_le32(desired_access);
@@ -906,6 +907,15 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
}
*persistent_fid = rsp->PersistentFileId;
*volatile_fid = rsp->VolatileFileId;
+
+ if (buf) {
+ memcpy(buf, &rsp->CreationTime, 32);
+ buf->AllocationSize = rsp->AllocationSize;
+ buf->EndOfFile = rsp->EndofFile;
+ buf->Attributes = rsp->FileAttributes;
+ buf->NumberOfLinks = cpu_to_le32(1);
+ buf->DeletePending = 0;
+ }
creat_exit:
free_rsp_buf(resp_buftype, rsp);
return rc;
@@ -1019,10 +1029,10 @@ validate_and_copy_buf(unsigned int offset, unsigned int buffer_length,
return 0;
}
-int
-SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- struct smb2_file_all_info *data)
+static int
+query_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, u8 info_class,
+ size_t output_len, size_t min_len, void *data)
{
struct smb2_query_info_req *req;
struct smb2_query_info_rsp *rsp = NULL;
@@ -1044,14 +1054,13 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
req->InfoType = SMB2_O_INFO_FILE;
- req->FileInfoClass = FILE_ALL_INFORMATION;
+ req->FileInfoClass = info_class;
req->PersistentFileId = persistent_fid;
req->VolatileFileId = volatile_fid;
/* 4 for rfc1002 length field and 1 for Buffer */
req->InputBufferOffset =
cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
- req->OutputBufferLength =
- cpu_to_le32(sizeof(struct smb2_file_all_info) + MAX_NAME * 2);
+ req->OutputBufferLength = cpu_to_le32(output_len);
iov[0].iov_base = (char *)req;
/* 4 for rfc1002 length field */
@@ -1067,14 +1076,34 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
le32_to_cpu(rsp->OutputBufferLength),
- &rsp->hdr, sizeof(struct smb2_file_all_info),
- (char *)data);
+ &rsp->hdr, min_len, data);
qinf_exit:
free_rsp_buf(resp_buftype, rsp);
return rc;
}
+int
+SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ struct smb2_file_all_info *data)
+{
+ return query_info(xid, tcon, persistent_fid, volatile_fid,
+ FILE_ALL_INFORMATION,
+ sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+ sizeof(struct smb2_file_all_info), data);
+}
+
+int
+SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
+{
+ return query_info(xid, tcon, persistent_fid, volatile_fid,
+ FILE_INTERNAL_INFORMATION,
+ sizeof(struct smb2_file_internal_info),
+ sizeof(struct smb2_file_internal_info), uniqueid);
+}
+
/*
* This is a no-op for now. We're not really interested in the reply, but
* rather in the fact that the server sent one and that server->lstrp
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index f37a1b4..7f1caff 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -546,6 +546,10 @@ struct smb2_query_info_rsp {
#define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50
#define FILE_STANDARD_LINK_INFORMATION 54
+struct smb2_file_internal_info {
+ __le64 IndexNumber;
+} __packed; /* level 6 Query */
+
/*
* This level 18, although with struct with same name is different from cifs
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f4ac727..624d344 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -48,6 +48,8 @@ extern int smb2_setup_async_request(struct TCP_Server_Info *server,
struct mid_q_entry **ret_mid);
extern void smb2_echo_request(struct work_struct *work);
+extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
+ struct smb2_file_all_info *src);
extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path, FILE_ALL_INFO *data,
@@ -62,6 +64,12 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *full_path, int disposition,
+ int desired_access, int create_options,
+ struct cifs_fid *fid, __u32 *oplock,
+ FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+
/*
* SMB2 Worker functions - most of protocol specific implementation details
* are contained within these calls.
@@ -77,12 +85,16 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
__le16 *path, u64 *persistent_fid, u64 *volatile_fid,
__u32 desired_access, __u32 create_disposition,
- __u32 file_attributes, __u32 create_options);
+ __u32 file_attributes, __u32 create_options,
+ struct smb2_file_all_info *buf);
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id);
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
struct smb2_file_all_info *data);
+extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ __le64 *uniqueid);
extern int SMB2_echo(struct TCP_Server_Info *server);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 14/45] CIFS: Move guery file info code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (12 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 13/45] CIFS: Add open/close file support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 15/45] CIFS: Add SMB2 support for query_file_info Pavel Shilovsky
` (31 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
and make cifs_get_file_info(_unix) calls static.
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 +++
fs/cifs/cifsproto.h | 2 --
fs/cifs/inode.c | 12 +++++++++---
fs/cifs/smb1ops.c | 8 ++++++++
4 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index bd2b397..0467e38 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -236,6 +236,9 @@ struct smb_version_operations {
int (*query_path_info)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *,
FILE_ALL_INFO *, bool *);
+ /* query file data from the server */
+ int (*query_file_info)(const unsigned int, struct cifs_tcon *,
+ struct cifs_fid *, FILE_ALL_INFO *);
/* get server index number */
int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 80b0e40..c811f66 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -137,11 +137,9 @@ extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
extern struct inode *cifs_iget(struct super_block *sb,
struct cifs_fattr *fattr);
-extern int cifs_get_file_info(struct file *filp);
extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
int xid, const __u16 *fid);
-extern int cifs_get_file_info_unix(struct file *filp);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
struct super_block *sb, unsigned int xid);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 1eeb6a0..39ef1a6 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -286,7 +286,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
}
-int cifs_get_file_info_unix(struct file *filp)
+static int
+cifs_get_file_info_unix(struct file *filp)
{
int rc;
unsigned int xid;
@@ -554,7 +555,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
fattr->cf_gid = cifs_sb->mnt_gid;
}
-int cifs_get_file_info(struct file *filp)
+static int
+cifs_get_file_info(struct file *filp)
{
int rc;
unsigned int xid;
@@ -564,9 +566,13 @@ int cifs_get_file_info(struct file *filp)
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifsFileInfo *cfile = filp->private_data;
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ struct TCP_Server_Info *server = tcon->ses->server;
+
+ if (!server->ops->query_file_info)
+ return -ENOSYS;
xid = get_xid();
- rc = CIFSSMBQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
+ rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
switch (rc) {
case 0:
cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index bb75847..cbbc122 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -489,6 +489,13 @@ cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
+static int
+cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+ return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data);
+}
+
static char *
cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon)
@@ -672,6 +679,7 @@ struct smb_version_operations smb1_operations = {
.qfs_tcon = cifs_qfs_tcon,
.is_path_accessible = cifs_is_path_accessible,
.query_path_info = cifs_query_path_info,
+ .query_file_info = cifs_query_file_info,
.get_srv_inum = cifs_get_srv_inum,
.build_path_to_root = cifs_build_path_to_root,
.echo = CIFSSMBEcho,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 15/45] CIFS: Add SMB2 support for query_file_info
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (13 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 14/45] CIFS: Move guery file info code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 16/45] CIFS: Move create code use ops struct Pavel Shilovsky
` (30 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2ops.c | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index eba12b3..0fd5801 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -190,6 +190,26 @@ smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
return 0;
}
+static int
+smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+ int rc;
+ struct smb2_file_all_info *smb2_data;
+
+ smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+ GFP_KERNEL);
+ if (smb2_data == NULL)
+ return -ENOMEM;
+
+ rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid,
+ smb2_data);
+ if (!rc)
+ move_smb2_info_to_cifs(data, smb2_data);
+ kfree(smb2_data);
+ return rc;
+}
+
static char *
smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
struct cifs_tcon *tcon)
@@ -334,6 +354,7 @@ struct smb_version_operations smb21_operations = {
.echo = SMB2_echo,
.query_path_info = smb2_query_path_info,
.get_srv_inum = smb2_get_srv_inum,
+ .query_file_info = smb2_query_file_info,
.build_path_to_root = smb2_build_path_to_root,
.mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 16/45] CIFS: Move create code use ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (14 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 15/45] CIFS: Add SMB2 support for query_file_info Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 17/45] CIFS: Move reopen code to " Pavel Shilovsky
` (29 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/dir.c | 94 ++++++++++++++++++++++++++++------------------------
fs/cifs/file.c | 10 +++---
fs/cifs/smb1ops.c | 2 +-
3 files changed, 57 insertions(+), 49 deletions(-)
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index eebffaf..7265e5a 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -160,17 +160,18 @@ check_name(struct dentry *direntry)
static int
cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
struct tcon_link *tlink, unsigned oflags, umode_t mode,
- __u32 *oplock, __u16 *fileHandle, int *created)
+ __u32 *oplock, struct cifs_fid *fid, int *created)
{
int rc = -ENOENT;
int create_options = CREATE_NOT_DIR;
- int desiredAccess;
+ int desired_access;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_tcon *tcon = tlink_tcon(tlink);
char *full_path = NULL;
FILE_ALL_INFO *buf = NULL;
struct inode *newinode = NULL;
int disposition;
+ struct TCP_Server_Info *server = tcon->ses->server;
*oplock = 0;
if (tcon->ses->server->oplocks)
@@ -185,8 +186,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
- rc = cifs_posix_open(full_path, &newinode,
- inode->i_sb, mode, oflags, oplock, fileHandle, xid);
+ rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode,
+ oflags, oplock, &fid->netfid, xid);
switch (rc) {
case 0:
if (newinode == NULL) {
@@ -202,7 +203,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
* close it and proceed as if it were a normal
* lookup.
*/
- CIFSSMBClose(xid, tcon, *fileHandle);
+ CIFSSMBClose(xid, tcon, fid->netfid);
goto cifs_create_get_file_info;
}
/* success, no need to query */
@@ -244,11 +245,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
*/
}
- desiredAccess = 0;
+ desired_access = 0;
if (OPEN_FMODE(oflags) & FMODE_READ)
- desiredAccess |= GENERIC_READ; /* is this too little? */
+ desired_access |= GENERIC_READ; /* is this too little? */
if (OPEN_FMODE(oflags) & FMODE_WRITE)
- desiredAccess |= GENERIC_WRITE;
+ desired_access |= GENERIC_WRITE;
disposition = FILE_OVERWRITE_IF;
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
@@ -260,8 +261,15 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
else
cFYI(1, "Create flag not set in create function");
- /* BB add processing to set equivalent of mode - e.g. via CreateX with
- ACLs */
+ /*
+ * BB add processing to set equivalent of mode - e.g. via CreateX with
+ * ACLs
+ */
+
+ if (!server->ops->open) {
+ rc = -ENOSYS;
+ goto out;
+ }
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (buf == NULL) {
@@ -279,28 +287,18 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
- if (tcon->ses->capabilities & CAP_NT_SMBS)
- rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
- desiredAccess, create_options,
- fileHandle, oplock, buf, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- else
- rc = -EIO; /* no NT SMB support fall into legacy open below */
-
- if (rc == -EIO) {
- /* old server, retry the open legacy style */
- rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
- desiredAccess, create_options,
- fileHandle, oplock, buf, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- }
+ rc = server->ops->open(xid, tcon, full_path, disposition,
+ desired_access, create_options, fid, oplock,
+ buf, cifs_sb);
if (rc) {
cFYI(1, "cifs_create returned 0x%x", rc);
goto out;
}
- /* If Open reported that we actually created a file
- then we now have to set the mode if possible */
+ /*
+ * If Open reported that we actually created a file then we now have to
+ * set the mode if possible.
+ */
if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
struct cifs_unix_set_info_args args = {
.mode = mode,
@@ -321,11 +319,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
args.uid = NO_CHANGE_64;
args.gid = NO_CHANGE_64;
}
- CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
- current->tgid);
+ CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid,
+ current->tgid);
} else {
- /* BB implement mode setting via Windows security
- descriptors e.g. */
+ /*
+ * BB implement mode setting via Windows security
+ * descriptors e.g.
+ */
/* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
/* Could set r/o dos attribute if mode & 0222 == 0 */
@@ -334,11 +334,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
cifs_create_get_file_info:
/* server might mask mode so we have to query for it */
if (tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb, xid);
+ rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+ xid);
else {
- rc = cifs_get_inode_info(&newinode, full_path, buf,
- inode->i_sb, xid, fileHandle);
+ rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
+ xid, &fid->netfid);
if (newinode) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
newinode->i_mode = mode;
@@ -364,7 +364,7 @@ cifs_create_set_dentry:
/* ENOENT for create? How weird... */
rc = -ENOENT;
if (!newinode) {
- CIFSSMBClose(xid, tcon, *fileHandle);
+ CIFSSMBClose(xid, tcon, fid->netfid);
goto out;
}
rc = 0;
@@ -384,6 +384,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
unsigned int xid;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct cifs_fid fid;
__u32 oplock;
struct cifsFileInfo *file_info;
@@ -421,22 +422,25 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
goto out_free_xid;
tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fid.netfid, opened);
+ &oplock, &fid, opened);
if (rc)
goto out;
rc = finish_open(file, direntry, generic_file_open, opened);
if (rc) {
- CIFSSMBClose(xid, tcon, fid.netfid);
+ if (server->ops->close)
+ server->ops->close(xid, tcon, &fid);
goto out;
}
file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
if (file_info == NULL) {
- CIFSSMBClose(xid, tcon, fid.netfid);
+ if (server->ops->close)
+ server->ops->close(xid, tcon, &fid);
rc = -ENOMEM;
}
@@ -461,7 +465,9 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
*/
unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
struct tcon_link *tlink;
- __u16 fileHandle;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
+ struct cifs_fid fid;
__u32 oplock;
int created = FILE_CREATED;
@@ -474,9 +480,11 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
goto out_free_xid;
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
- &oplock, &fileHandle, &created);
- if (!rc)
- CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
+ &oplock, &fid, &created);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+ if (!rc && server->ops->close)
+ server->ops->close(xid, tcon, &fid);
cifs_put_tlink(tlink);
out_free_xid:
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index b18b36a..e11a58a 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -303,13 +303,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
if (list_empty(&cifsi->openFileList)) {
cFYI(1, "closing last open instance for inode %p",
cifs_file->dentry->d_inode);
-
- /* in strict cache mode we need invalidate mapping on the last
- close because it may cause a error when we open this file
- again and get at least level II oplock */
+ /*
+ * In strict cache mode we need invalidate mapping on the last
+ * close because it may cause a error when we open this file
+ * again and get at least level II oplock.
+ */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
CIFS_I(inode)->invalid_mapping = true;
-
cifs_set_oplock_level(cifsi, 0);
}
spin_unlock(&cifs_file_list_lock);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index cbbc122..dd64754 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -622,7 +622,7 @@ cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
{
if (!(tcon->ses->capabilities & CAP_NT_SMBS))
return SMBLegacyOpen(xid, tcon, path, disposition,
- desired_access, CREATE_NOT_DIR,
+ desired_access, create_options,
&fid->netfid, oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR);
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 17/45] CIFS: Move reopen code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (15 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 16/45] CIFS: Move create code use ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 18/45] CIFS: Make flush code use " Pavel Shilovsky
` (28 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/file.c | 123 +++++++++++++++++++++++++++++--------------------------
1 files changed, 65 insertions(+), 58 deletions(-)
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e11a58a..e8cca00 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -450,59 +450,66 @@ out:
return rc;
}
-/* Try to reacquire byte range locks that were released when session */
-/* to server was lost */
+/*
+ * Try to reacquire byte range locks that were released when session
+ * to server was lost
+ */
static int cifs_relock_file(struct cifsFileInfo *cifsFile)
{
int rc = 0;
-/* BB list all locks open on this file and relock */
+ /* BB list all locks open on this file and relock */
return rc;
}
-static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
+static int
+cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
{
int rc = -EACCES;
unsigned int xid;
__u32 oplock;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
- struct cifsInodeInfo *pCifsInode;
+ struct TCP_Server_Info *server;
+ struct cifsInodeInfo *cinode;
struct inode *inode;
char *full_path = NULL;
- int desiredAccess;
+ int desired_access;
int disposition = FILE_OPEN;
int create_options = CREATE_NOT_DIR;
- __u16 netfid;
+ struct cifs_fid fid;
xid = get_xid();
- mutex_lock(&pCifsFile->fh_mutex);
- if (!pCifsFile->invalidHandle) {
- mutex_unlock(&pCifsFile->fh_mutex);
+ mutex_lock(&cfile->fh_mutex);
+ if (!cfile->invalidHandle) {
+ mutex_unlock(&cfile->fh_mutex);
rc = 0;
free_xid(xid);
return rc;
}
- inode = pCifsFile->dentry->d_inode;
+ inode = cfile->dentry->d_inode;
cifs_sb = CIFS_SB(inode->i_sb);
- tcon = tlink_tcon(pCifsFile->tlink);
+ tcon = tlink_tcon(cfile->tlink);
+ server = tcon->ses->server;
-/* can not grab rename sem here because various ops, including
- those that already have the rename sem can end up causing writepage
- to get called and if the server was down that means we end up here,
- and we can never tell if the caller already has the rename_sem */
- full_path = build_path_from_dentry(pCifsFile->dentry);
+ /*
+ * Can not grab rename sem here because various ops, including those
+ * that already have the rename sem can end up causing writepage to get
+ * called and if the server was down that means we end up here, and we
+ * can never tell if the caller already has the rename_sem.
+ */
+ full_path = build_path_from_dentry(cfile->dentry);
if (full_path == NULL) {
rc = -ENOMEM;
- mutex_unlock(&pCifsFile->fh_mutex);
+ mutex_unlock(&cfile->fh_mutex);
free_xid(xid);
return rc;
}
- cFYI(1, "inode = 0x%p file flags 0x%x for %s",
- inode, pCifsFile->f_flags, full_path);
+ cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, cfile->f_flags,
+ full_path);
if (tcon->ses->server->oplocks)
oplock = REQ_OPLOCK;
@@ -516,69 +523,69 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
* O_CREAT, O_EXCL and O_TRUNC already had their effect on the
* original open. Must mask them off for a reopen.
*/
- unsigned int oflags = pCifsFile->f_flags &
+ unsigned int oflags = cfile->f_flags &
~(O_CREAT | O_EXCL | O_TRUNC);
rc = cifs_posix_open(full_path, NULL, inode->i_sb,
- cifs_sb->mnt_file_mode /* ignored */,
- oflags, &oplock, &netfid, xid);
+ cifs_sb->mnt_file_mode /* ignored */,
+ oflags, &oplock, &fid.netfid, xid);
if (rc == 0) {
cFYI(1, "posix reopen succeeded");
goto reopen_success;
}
- /* fallthrough to retry open the old way on errors, especially
- in the reconnect path it is important to retry hard */
+ /*
+ * fallthrough to retry open the old way on errors, especially
+ * in the reconnect path it is important to retry hard
+ */
}
- desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
+ desired_access = cifs_convert_flags(cfile->f_flags);
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
- /* Can not refresh inode by passing in file_info buf to be returned
- by SMBOpen and then calling get_inode_info with returned buf
- since file might have write behind data that needs to be flushed
- and server version of file size can be stale. If we knew for sure
- that inode was not dirty locally we could do this */
-
- rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
- create_options, &netfid, &oplock, NULL,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ /*
+ * Can not refresh inode by passing in file_info buf to be returned by
+ * CIFSSMBOpen and then calling get_inode_info with returned buf since
+ * file might have write behind data that needs to be flushed and server
+ * version of file size can be stale. If we knew for sure that inode was
+ * not dirty locally we could do this.
+ */
+ rc = server->ops->open(xid, tcon, full_path, disposition,
+ desired_access, create_options, &fid, &oplock,
+ NULL, cifs_sb);
if (rc) {
- mutex_unlock(&pCifsFile->fh_mutex);
- cFYI(1, "cifs_open returned 0x%x", rc);
+ mutex_unlock(&cfile->fh_mutex);
+ cFYI(1, "cifs_reopen returned 0x%x", rc);
cFYI(1, "oplock: %d", oplock);
goto reopen_error_exit;
}
reopen_success:
- pCifsFile->fid.netfid = netfid;
- pCifsFile->invalidHandle = false;
- mutex_unlock(&pCifsFile->fh_mutex);
- pCifsInode = CIFS_I(inode);
+ cfile->invalidHandle = false;
+ mutex_unlock(&cfile->fh_mutex);
+ cinode = CIFS_I(inode);
if (can_flush) {
rc = filemap_write_and_wait(inode->i_mapping);
mapping_set_error(inode->i_mapping, rc);
if (tcon->unix_ext)
- rc = cifs_get_inode_info_unix(&inode,
- full_path, inode->i_sb, xid);
+ rc = cifs_get_inode_info_unix(&inode, full_path,
+ inode->i_sb, xid);
else
- rc = cifs_get_inode_info(&inode,
- full_path, NULL, inode->i_sb,
- xid, NULL);
- } /* else we are writing out data to server already
- and could deadlock if we tried to flush data, and
- since we do not know if we have data that would
- invalidate the current end of file on the server
- we can not go to the server to get the new inod
- info */
-
- cifs_set_oplock_level(pCifsInode, oplock);
-
- cifs_relock_file(pCifsFile);
+ rc = cifs_get_inode_info(&inode, full_path, NULL,
+ inode->i_sb, xid, NULL);
+ }
+ /*
+ * Else we are writing out data to server already and could deadlock if
+ * we tried to flush data, and since we do not know if we have data that
+ * would invalidate the current end of file on the server we can not go
+ * to the server to get the new inode info.
+ */
+
+ server->ops->set_fid(cfile, &fid, oplock);
+ cifs_relock_file(cfile);
reopen_error_exit:
kfree(full_path);
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 18/45] CIFS: Make flush code use ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (16 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 17/45] CIFS: Move reopen code to " Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 19/45] CIFS: Add SMB2 support for flush Pavel Shilovsky
` (27 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 2 ++
fs/cifs/file.c | 20 ++++++++++++++++----
fs/cifs/smb1ops.c | 8 ++++++++
3 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0467e38..3d94397 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -274,6 +274,8 @@ struct smb_version_operations {
void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
/* close a file */
int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+ /* send a flush request to the server */
+ int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
};
struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index e8cca00..3f2cfb3 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2055,6 +2055,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
unsigned int xid;
int rc = 0;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct cifsFileInfo *smbfile = file->private_data;
struct inode *inode = file->f_path.dentry->d_inode;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2078,8 +2079,13 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
}
tcon = tlink_tcon(smbfile->tlink);
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
- rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+ server = tcon->ses->server;
+ if (server->ops->flush)
+ rc = server->ops->flush(xid, tcon, &smbfile->fid);
+ else
+ rc = -ENOSYS;
+ }
free_xid(xid);
mutex_unlock(&inode->i_mutex);
@@ -2091,6 +2097,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
unsigned int xid;
int rc = 0;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct cifsFileInfo *smbfile = file->private_data;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
struct inode *inode = file->f_mapping->host;
@@ -2106,8 +2113,13 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
file->f_path.dentry->d_name.name, datasync);
tcon = tlink_tcon(smbfile->tlink);
- if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
- rc = CIFSSMBFlush(xid, tcon, smbfile->fid.netfid);
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+ server = tcon->ses->server;
+ if (server->ops->flush)
+ rc = server->ops->flush(xid, tcon, &smbfile->fid);
+ else
+ rc = -ENOSYS;
+ }
free_xid(xid);
mutex_unlock(&inode->i_mutex);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index dd64754..df20dd9 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -648,6 +648,13 @@ cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
return CIFSSMBClose(xid, tcon, fid->netfid);
}
+static int
+cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid)
+{
+ return CIFSSMBFlush(xid, tcon, fid->netfid);
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -691,6 +698,7 @@ struct smb_version_operations smb1_operations = {
.open = cifs_open_file,
.set_fid = cifs_set_fid,
.close = cifs_close_file,
+ .flush = cifs_flush_file,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 19/45] CIFS: Add SMB2 support for flush
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (17 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 18/45] CIFS: Make flush code use " Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct Pavel Shilovsky
` (26 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2ops.c | 8 ++++++++
fs/cifs/smb2pdu.c | 38 ++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 15 +++++++++++++++
fs/cifs/smb2proto.h | 2 ++
4 files changed, 63 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0fd5801..d81e1da 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -329,6 +329,13 @@ smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
}
+static int
+smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid)
+{
+ return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -363,6 +370,7 @@ struct smb_version_operations smb21_operations = {
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
+ .flush = smb2_flush_file,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 231e970..ff37406 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1152,3 +1152,41 @@ SMB2_echo(struct TCP_Server_Info *server)
cifs_small_buf_release(req);
return rc;
}
+
+int
+SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+ u64 volatile_fid)
+{
+ struct smb2_flush_req *req;
+ struct TCP_Server_Info *server;
+ struct cifs_ses *ses = tcon->ses;
+ struct kvec iov[1];
+ int resp_buftype;
+ int rc = 0;
+
+ cFYI(1, "Flush");
+
+ if (ses && (ses->server))
+ server = ses->server;
+ else
+ return -EIO;
+
+ rc = small_smb2_init(SMB2_FLUSH, tcon, (void **) &req);
+ if (rc)
+ return rc;
+
+ req->PersistentFileId = persistent_fid;
+ req->VolatileFileId = volatile_fid;
+
+ iov[0].iov_base = (char *)req;
+ /* 4 for rfc1002 length field */
+ iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+ rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+
+ if ((rc != 0) && tcon)
+ cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
+
+ free_rsp_buf(resp_buftype, iov[0].iov_base);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 7f1caff..af2c996 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -451,6 +451,21 @@ struct smb2_close_rsp {
__le32 Attributes;
} __packed;
+struct smb2_flush_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 24 */
+ __le16 Reserved1;
+ __le32 Reserved2;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+} __packed;
+
+struct smb2_flush_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize;
+ __le16 Reserved;
+} __packed;
+
struct smb2_echo_req {
struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 4 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 624d344..51e6cd1 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -89,6 +89,8 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
struct smb2_file_all_info *buf);
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id);
+extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_file_id, u64 volatile_file_id);
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id,
struct smb2_file_all_info *data);
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (18 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 19/45] CIFS: Add SMB2 support for flush Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating Pavel Shilovsky
` (25 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
---
fs/cifs/cifsglob.h | 61 ++++++++++++++++++++++
fs/cifs/connect.c | 144 +---------------------------------------------------
fs/cifs/smb1ops.c | 86 +++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 142 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3d94397..797c17a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -213,6 +213,10 @@ struct smb_version_operations {
bool (*need_neg)(struct TCP_Server_Info *);
/* negotiate to the server */
int (*negotiate)(const unsigned int, struct cifs_ses *);
+ /* set negotiated write size */
+ unsigned int (*negotiate_wsize)(struct cifs_tcon *, struct smb_vol *);
+ /* set negotiated read size */
+ unsigned int (*negotiate_rsize)(struct cifs_tcon *, struct smb_vol *);
/* setup smb sessionn */
int (*sess_setup)(const unsigned int, struct cifs_ses *,
const struct nls_table *);
@@ -516,6 +520,63 @@ get_next_mid(struct TCP_Server_Info *server)
}
/*
+ * When the server supports very large reads and writes via POSIX extensions,
+ * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
+ * including the RFC1001 length.
+ *
+ * Note that this might make for "interesting" allocation problems during
+ * writeback however as we have to allocate an array of pointers for the
+ * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ *
+ * For reads, there is a similar problem as we need to allocate an array
+ * of kvecs to handle the receive, though that should only need to be done
+ * once.
+ */
+#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
+
+/*
+ * When the server doesn't allow large posix writes, only allow a rsize/wsize
+ * of 2^17-1 minus the size of the call header. That allows for a read or
+ * write up to the maximum size described by RFC1002.
+ */
+#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
+
+/*
+ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+ * a single wsize request with a single call.
+ */
+#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
+
+/*
+ * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
+ * those values when posix extensions aren't in force. In actuality here, we
+ * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
+ * to be ok with the extra byte even though Windows doesn't send writes that
+ * are that large.
+ *
+ * Citation:
+ *
+ * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
+ */
+#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
+#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
+
+/*
+ * On hosts with high memory, we can't currently support wsize/rsize that are
+ * larger than we can kmap at once. Cap the rsize/wsize at
+ * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
+ * larger than that anyway.
+ */
+#ifdef CONFIG_HIGHMEM
+#define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE)
+#else /* CONFIG_HIGHMEM */
+#define CIFS_KMAP_SIZE_LIMIT (1<<24)
+#endif /* CONFIG_HIGHMEM */
+
+/*
* Macros to allow the TCP_Server_Info->net field and related code to drop out
* when CONFIG_NET_NS isn't set.
*/
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 99d50bf..bd4dcdd 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -3260,146 +3260,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
"mount option supported");
}
-/*
- * When the server supports very large reads and writes via POSIX extensions,
- * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
- * including the RFC1001 length.
- *
- * Note that this might make for "interesting" allocation problems during
- * writeback however as we have to allocate an array of pointers for the
- * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
- *
- * For reads, there is a similar problem as we need to allocate an array
- * of kvecs to handle the receive, though that should only need to be done
- * once.
- */
-#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
-
-/*
- * When the server doesn't allow large posix writes, only allow a rsize/wsize
- * of 2^17-1 minus the size of the call header. That allows for a read or
- * write up to the maximum size described by RFC1002.
- */
-#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
-
-/*
- * The default wsize is 1M. find_get_pages seems to return a maximum of 256
- * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
- * a single wsize request with a single call.
- */
-#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
-
-/*
- * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
- * those values when posix extensions aren't in force. In actuality here, we
- * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
- * to be ok with the extra byte even though Windows doesn't send writes that
- * are that large.
- *
- * Citation:
- *
- * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
- */
-#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
-#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
-
-/*
- * On hosts with high memory, we can't currently support wsize/rsize that are
- * larger than we can kmap at once. Cap the rsize/wsize at
- * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
- * larger than that anyway.
- */
-#ifdef CONFIG_HIGHMEM
-#define CIFS_KMAP_SIZE_LIMIT (LAST_PKMAP * PAGE_CACHE_SIZE)
-#else /* CONFIG_HIGHMEM */
-#define CIFS_KMAP_SIZE_LIMIT (1<<24)
-#endif /* CONFIG_HIGHMEM */
-
-static unsigned int
-cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
- __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
- struct TCP_Server_Info *server = tcon->ses->server;
- unsigned int wsize;
-
- /* start with specified wsize, or default */
- if (pvolume_info->wsize)
- wsize = pvolume_info->wsize;
- else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
- wsize = CIFS_DEFAULT_IOSIZE;
- else
- wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
-
- /* can server support 24-bit write sizes? (via UNIX extensions) */
- if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
- wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
-
- /*
- * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
- * Limit it to max buffer offered by the server, minus the size of the
- * WRITEX header, not including the 4 byte RFC1001 length.
- */
- if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
- (!(server->capabilities & CAP_UNIX) &&
- (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
- wsize = min_t(unsigned int, wsize,
- server->maxBuf - sizeof(WRITE_REQ) + 4);
-
- /* limit to the amount that we can kmap at once */
- wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
-
- /* hard limit of CIFS_MAX_WSIZE */
- wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
-
- return wsize;
-}
-
-static unsigned int
-cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
- __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
- struct TCP_Server_Info *server = tcon->ses->server;
- unsigned int rsize, defsize;
-
- /*
- * Set default value...
- *
- * HACK alert! Ancient servers have very small buffers. Even though
- * MS-CIFS indicates that servers are only limited by the client's
- * bufsize for reads, testing against win98se shows that it throws
- * INVALID_PARAMETER errors if you try to request too large a read.
- * OS/2 just sends back short reads.
- *
- * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
- * it can't handle a read request larger than its MaxBufferSize either.
- */
- if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
- defsize = CIFS_DEFAULT_IOSIZE;
- else if (server->capabilities & CAP_LARGE_READ_X)
- defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
- else
- defsize = server->maxBuf - sizeof(READ_RSP);
-
- rsize = pvolume_info->rsize ? pvolume_info->rsize : defsize;
-
- /*
- * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
- * the client's MaxBufferSize.
- */
- if (!(server->capabilities & CAP_LARGE_READ_X))
- rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
-
- /* limit to the amount that we can kmap at once */
- rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
-
- /* hard limit of CIFS_MAX_RSIZE */
- rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
-
- return rsize;
-}
-
static void
cleanup_volume_info_contents(struct smb_vol *volume_info)
{
@@ -3650,8 +3510,8 @@ try_mount_again:
if (!tcon->ipc && server->ops->qfs_tcon)
server->ops->qfs_tcon(xid, tcon);
- cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
- cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info);
+ cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info);
+ cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info);
/* tune readahead according to rsize */
cifs_sb->bdi.ra_pages = cifs_sb->rsize / PAGE_CACHE_SIZE;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index df20dd9..7e8a2bd 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/pagemap.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -410,6 +411,89 @@ cifs_negotiate(const unsigned int xid, struct cifs_ses *ses)
return rc;
}
+static unsigned int
+cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+ __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+ struct TCP_Server_Info *server = tcon->ses->server;
+ unsigned int wsize;
+
+ /* start with specified wsize, or default */
+ if (volume_info->wsize)
+ wsize = volume_info->wsize;
+ else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+ wsize = CIFS_DEFAULT_IOSIZE;
+ else
+ wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
+
+ /* can server support 24-bit write sizes? (via UNIX extensions) */
+ if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+ wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
+
+ /*
+ * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
+ * Limit it to max buffer offered by the server, minus the size of the
+ * WRITEX header, not including the 4 byte RFC1001 length.
+ */
+ if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
+ (!(server->capabilities & CAP_UNIX) &&
+ (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+ wsize = min_t(unsigned int, wsize,
+ server->maxBuf - sizeof(WRITE_REQ) + 4);
+
+ /* limit to the amount that we can kmap at once */
+ wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
+
+ /* hard limit of CIFS_MAX_WSIZE */
+ wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
+
+ return wsize;
+}
+
+static unsigned int
+cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+ __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+ struct TCP_Server_Info *server = tcon->ses->server;
+ unsigned int rsize, defsize;
+
+ /*
+ * Set default value...
+ *
+ * HACK alert! Ancient servers have very small buffers. Even though
+ * MS-CIFS indicates that servers are only limited by the client's
+ * bufsize for reads, testing against win98se shows that it throws
+ * INVALID_PARAMETER errors if you try to request too large a read.
+ * OS/2 just sends back short reads.
+ *
+ * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
+ * it can't handle a read request larger than its MaxBufferSize either.
+ */
+ if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
+ defsize = CIFS_DEFAULT_IOSIZE;
+ else if (server->capabilities & CAP_LARGE_READ_X)
+ defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
+ else
+ defsize = server->maxBuf - sizeof(READ_RSP);
+
+ rsize = volume_info->rsize ? volume_info->rsize : defsize;
+
+ /*
+ * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
+ * the client's MaxBufferSize.
+ */
+ if (!(server->capabilities & CAP_LARGE_READ_X))
+ rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
+
+ /* limit to the amount that we can kmap at once */
+ rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
+
+ /* hard limit of CIFS_MAX_RSIZE */
+ rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
+
+ return rsize;
+}
+
static void
cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
{
@@ -678,6 +762,8 @@ struct smb_version_operations smb1_operations = {
.check_trans2 = cifs_check_trans2,
.need_neg = cifs_need_neg,
.negotiate = cifs_negotiate,
+ .negotiate_wsize = cifs_negotiate_wsize,
+ .negotiate_rsize = cifs_negotiate_rsize,
.sess_setup = CIFS_SessSetup,
.logoff = CIFSSMBLogoff,
.tree_connect = CIFSTCon,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (19 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 20/45] CIFS: Move r/wsize negotiating to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 22/45] CIFS: Move async read to ops struct Pavel Shilovsky
` (24 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
---
fs/cifs/smb2ops.c | 36 ++++++++++++++++++++++++++++++++++++
1 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index d81e1da..c0997ad 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -157,6 +157,40 @@ smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
return rc;
}
+static unsigned int
+smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+ struct TCP_Server_Info *server = tcon->ses->server;
+ unsigned int wsize;
+
+ /* start with specified wsize, or default */
+ wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
+ wsize = min_t(unsigned int, wsize, server->max_write);
+ /*
+ * limit write size to 2 ** 16, because we don't support multicredit
+ * requests now.
+ */
+ wsize = min_t(unsigned int, wsize, 2 << 15);
+ return wsize;
+}
+
+static unsigned int
+smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+ struct TCP_Server_Info *server = tcon->ses->server;
+ unsigned int rsize;
+
+ /* start with specified rsize, or default */
+ rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
+ rsize = min_t(unsigned int, rsize, server->max_read);
+ /*
+ * limit write size to 2 ** 16, because we don't support multicredit
+ * requests now.
+ */
+ rsize = min_t(unsigned int, rsize, 2 << 15);
+ return rsize;
+}
+
static int
smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -352,6 +386,8 @@ struct smb_version_operations smb21_operations = {
.print_stats = smb2_print_stats,
.need_neg = smb2_need_neg,
.negotiate = smb2_negotiate,
+ .negotiate_wsize = smb2_negotiate_wsize,
+ .negotiate_rsize = smb2_negotiate_rsize,
.sess_setup = SMB2_sess_setup,
.logoff = SMB2_logoff,
.tree_connect = SMB2_tcon,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 22/45] CIFS: Move async read to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (20 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 21/45] CIFS: Add SMB2 r/wsize negotiating Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
` (23 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 +++
fs/cifs/file.c | 8 +++++++-
fs/cifs/smb1ops.c | 1 +
fs/cifs/smb2maperror.c | 3 ++-
4 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 797c17a..e71ab49 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -172,6 +172,7 @@ struct dfs_info3_param;
struct cifs_fattr;
struct smb_vol;
struct cifs_fid;
+struct cifs_readdata;
struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -280,6 +281,8 @@ struct smb_version_operations {
int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
/* send a flush request to the server */
int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+ /* async read from the server */
+ int (*async_readv)(struct cifs_readdata *);
};
struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 3f2cfb3..81403ad 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2481,6 +2481,9 @@ static int
cifs_retry_async_readv(struct cifs_readdata *rdata)
{
int rc;
+ struct TCP_Server_Info *server;
+
+ server = tlink_tcon(rdata->cfile->tlink)->ses->server;
do {
if (rdata->cfile->invalidHandle) {
@@ -2488,7 +2491,7 @@ cifs_retry_async_readv(struct cifs_readdata *rdata)
if (rc != 0)
continue;
}
- rc = cifs_async_readv(rdata);
+ rc = server->ops->async_readv(rdata);
} while (rc == -EAGAIN);
return rc;
@@ -2640,6 +2643,9 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
open_file = file->private_data;
tcon = tlink_tcon(open_file->tlink);
+ if (!tcon->ses->server->ops->async_readv)
+ return -ENOSYS;
+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
pid = open_file->pid;
else
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 7e8a2bd..e2dbd22 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -785,6 +785,7 @@ struct smb_version_operations smb1_operations = {
.set_fid = cifs_set_fid,
.close = cifs_close_file,
.flush = cifs_flush_file,
+ .async_readv = cifs_async_readv,
};
struct smb_version_values smb1_values = {
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index be41478..eaf5466 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -2455,7 +2455,8 @@ map_smb2_to_linux_error(char *buf, bool log_err)
return 0;
/* mask facility */
- if (log_err && (smb2err != (STATUS_MORE_PROCESSING_REQUIRED)))
+ if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
+ (smb2err != STATUS_END_OF_FILE))
smb2_print_status(smb2err);
else if (cifsFYI & CIFS_RC)
smb2_print_status(smb2err);
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (21 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 22/45] CIFS: Move async read to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 24/45] CIFS: Move async write to ops struct Pavel Shilovsky
` (22 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 25 +++++++++
fs/cifs/cifsproto.h | 20 +-------
fs/cifs/cifssmb.c | 2 +-
fs/cifs/smb2glob.h | 6 ++
fs/cifs/smb2misc.c | 3 +
fs/cifs/smb2ops.c | 19 +++++++
fs/cifs/smb2pdu.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 28 +++++++++++
fs/cifs/smb2proto.h | 1 +
9 files changed, 220 insertions(+), 20 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e71ab49..9ce1353 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -857,12 +857,37 @@ struct cifsFileInfo {
struct cifs_io_parms {
__u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+ __u64 persistent_fid; /* persist file id for smb2 */
+ __u64 volatile_fid; /* volatile file id for smb2 */
+#endif
__u32 pid;
__u64 offset;
unsigned int length;
struct cifs_tcon *tcon;
};
+struct cifs_readdata;
+
+/* asynchronous read support */
+struct cifs_readdata {
+ struct kref refcount;
+ struct list_head list;
+ struct completion done;
+ struct cifsFileInfo *cfile;
+ struct address_space *mapping;
+ __u64 offset;
+ unsigned int bytes;
+ pid_t pid;
+ int result;
+ struct list_head pages;
+ struct work_struct work;
+ int (*marshal_iov) (struct cifs_readdata *rdata,
+ unsigned int remaining);
+ unsigned int nr_iov;
+ struct kvec iov[1];
+};
+
/*
* Take a reference on the file private data. Must be called with
* cifs_file_list_lock held.
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index c811f66..949be72 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -463,27 +463,9 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
unsigned char *p24);
-/* asynchronous read support */
-struct cifs_readdata {
- struct kref refcount;
- struct list_head list;
- struct completion done;
- struct cifsFileInfo *cfile;
- struct address_space *mapping;
- __u64 offset;
- unsigned int bytes;
- pid_t pid;
- int result;
- struct list_head pages;
- struct work_struct work;
- int (*marshal_iov) (struct cifs_readdata *rdata,
- unsigned int remaining);
- unsigned int nr_iov;
- struct kvec iov[1];
-};
-
void cifs_readdata_release(struct kref *refcount);
int cifs_async_readv(struct cifs_readdata *rdata);
+int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
/* asynchronous write support */
struct cifs_writedata {
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 2936875..e37801c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1440,7 +1440,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
return 0;
}
-static int
+int
cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
{
int length, len;
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 33c1d89..11505d7 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -41,4 +41,10 @@
#define SMB2_OP_RENAME 6
#define SMB2_OP_DELETE 7
+/* Used when constructing chained read requests. */
+#define CHAINED_REQUEST 1
+#define START_OF_CHAIN 2
+#define END_OF_CHAIN 4
+#define RELATED_REQUEST 8
+
#endif /* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index a4ff5d5..cbb69e2 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -242,6 +242,9 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
((struct smb2_query_info_rsp *)hdr)->OutputBufferLength);
break;
case SMB2_READ:
+ *off = ((struct smb2_read_rsp *)hdr)->DataOffset;
+ *len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
+ break;
case SMB2_QUERY_DIRECTORY:
case SMB2_IOCTL:
case SMB2_CHANGE_NOTIFY:
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index c0997ad..ba4adf2 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -370,6 +370,20 @@ smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
}
+static unsigned int
+smb2_read_data_offset(char *buf)
+{
+ struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+ return rsp->DataOffset;
+}
+
+static unsigned int
+smb2_read_data_length(char *buf)
+{
+ struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+ return le32_to_cpu(rsp->DataLength);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -379,6 +393,9 @@ struct smb_version_operations smb21_operations = {
.get_credits_field = smb2_get_credits_field,
.get_credits = smb2_get_credits,
.get_next_mid = smb2_get_next_mid,
+ .read_data_offset = smb2_read_data_offset,
+ .read_data_length = smb2_read_data_length,
+ .map_error = map_smb2_to_linux_error,
.find_mid = smb2_find_mid,
.check_message = smb2_check_message,
.dump_detail = smb2_dump_detail,
@@ -407,12 +424,14 @@ struct smb_version_operations smb21_operations = {
.set_fid = smb2_set_fid,
.close = smb2_close_file,
.flush = smb2_flush_file,
+ .async_readv = smb2_async_readv,
};
struct smb_version_values smb21_values = {
.version_string = SMB21_VERSION_STRING,
.header_size = sizeof(struct smb2_hdr),
.max_header_size = MAX_SMB2_HDR_SIZE,
+ .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
.lock_cmd = SMB2_LOCK,
.cap_unix = 0,
.cap_nt_find = SMB2_NT_FIND,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index ff37406..69646ac 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -31,6 +31,7 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/vfs.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/uaccess.h>
#include <linux/xattr.h>
#include "smb2pdu.h"
@@ -42,6 +43,7 @@
#include "cifs_debug.h"
#include "ntlmssp.h"
#include "smb2status.h"
+#include "smb2glob.h"
/*
* The following table defines the expected "StructureSize" of SMB2 requests
@@ -1190,3 +1192,137 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
free_rsp_buf(resp_buftype, iov[0].iov_base);
return rc;
}
+
+/*
+ * To form a chain of read requests, any read requests after the first should
+ * have the end_of_chain boolean set to true.
+ */
+static int
+smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
+ unsigned int remaining_bytes, int request_type)
+{
+ int rc = -EACCES;
+ struct smb2_read_req *req = NULL;
+
+ rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req);
+ if (rc)
+ return rc;
+ if (io_parms->tcon->ses->server == NULL)
+ return -ECONNABORTED;
+
+ req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+ req->PersistentFileId = io_parms->persistent_fid;
+ req->VolatileFileId = io_parms->volatile_fid;
+ req->ReadChannelInfoOffset = 0; /* reserved */
+ req->ReadChannelInfoLength = 0; /* reserved */
+ req->Channel = 0; /* reserved */
+ req->MinimumCount = 0;
+ req->Length = cpu_to_le32(io_parms->length);
+ req->Offset = cpu_to_le64(io_parms->offset);
+
+ if (request_type & CHAINED_REQUEST) {
+ if (!(request_type & END_OF_CHAIN)) {
+ /* 4 for rfc1002 length field */
+ req->hdr.NextCommand =
+ cpu_to_le32(get_rfc1002_length(req) + 4);
+ } else /* END_OF_CHAIN */
+ req->hdr.NextCommand = 0;
+ if (request_type & RELATED_REQUEST) {
+ req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
+ /*
+ * Related requests use info from previous read request
+ * in chain.
+ */
+ req->hdr.SessionId = 0xFFFFFFFF;
+ req->hdr.TreeId = 0xFFFFFFFF;
+ req->PersistentFileId = 0xFFFFFFFF;
+ req->VolatileFileId = 0xFFFFFFFF;
+ }
+ }
+ if (remaining_bytes > io_parms->length)
+ req->RemainingBytes = cpu_to_le32(remaining_bytes);
+ else
+ req->RemainingBytes = 0;
+
+ iov[0].iov_base = (char *)req;
+ /* 4 for rfc1002 length field */
+ iov[0].iov_len = get_rfc1002_length(req) + 4;
+ return rc;
+}
+
+static void
+smb2_readv_callback(struct mid_q_entry *mid)
+{
+ struct cifs_readdata *rdata = mid->callback_data;
+ struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+ struct TCP_Server_Info *server = tcon->ses->server;
+ struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+ unsigned int credits_received = 1;
+
+ cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+ mid->mid, mid->mid_state, rdata->result, rdata->bytes);
+
+ switch (mid->mid_state) {
+ case MID_RESPONSE_RECEIVED:
+ credits_received = le16_to_cpu(buf->CreditRequest);
+ /* result already set, check signature */
+ /* if (server->sec_mode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if (smb2_verify_signature(mid->resp_buf, server))
+ cERROR(1, "Unexpected SMB signature"); */
+ /* FIXME: should this be counted toward the initiating task? */
+ task_io_account_read(rdata->bytes);
+ cifs_stats_bytes_read(tcon, rdata->bytes);
+ break;
+ case MID_REQUEST_SUBMITTED:
+ case MID_RETRY_NEEDED:
+ rdata->result = -EAGAIN;
+ break;
+ default:
+ rdata->result = -EIO;
+ }
+
+ if (rdata->result)
+ cifs_stats_fail_inc(tcon, SMB2_READ_HE);
+
+ queue_work(cifsiod_wq, &rdata->work);
+ DeleteMidQEntry(mid);
+ add_credits(server, credits_received, 0);
+}
+
+/* smb2_async_readv - send an async write, and set up mid to handle result */
+int
+smb2_async_readv(struct cifs_readdata *rdata)
+{
+ int rc;
+ struct smb2_hdr *buf;
+ struct cifs_io_parms io_parms;
+
+ cFYI(1, "%s: offset=%llu bytes=%u", __func__,
+ rdata->offset, rdata->bytes);
+
+ io_parms.tcon = tlink_tcon(rdata->cfile->tlink);
+ io_parms.offset = rdata->offset;
+ io_parms.length = rdata->bytes;
+ io_parms.persistent_fid = rdata->cfile->fid.persistent_fid;
+ io_parms.volatile_fid = rdata->cfile->fid.volatile_fid;
+ io_parms.pid = rdata->pid;
+ rc = smb2_new_read_req(&rdata->iov[0], &io_parms, 0, 0);
+ if (rc)
+ return rc;
+
+ buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+ /* 4 for rfc1002 length field */
+ rdata->iov[0].iov_len = get_rfc1002_length(rdata->iov[0].iov_base) + 4;
+
+ kref_get(&rdata->refcount);
+ rc = cifs_call_async(io_parms.tcon->ses->server, rdata->iov, 1,
+ cifs_readv_receive, smb2_readv_callback,
+ rdata, 0);
+ if (rc)
+ kref_put(&rdata->refcount, cifs_readdata_release);
+
+ cifs_small_buf_release(buf);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index af2c996..d73367c 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -466,6 +466,34 @@ struct smb2_flush_rsp {
__le16 Reserved;
} __packed;
+struct smb2_read_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 49 */
+ __u8 Padding; /* offset from start of SMB2 header to place read */
+ __u8 Reserved;
+ __le32 Length;
+ __le64 Offset;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ __le32 MinimumCount;
+ __le32 Channel; /* Reserved MBZ */
+ __le32 RemainingBytes;
+ __le16 ReadChannelInfoOffset; /* Reserved MBZ */
+ __le16 ReadChannelInfoLength; /* Reserved MBZ */
+ __u8 Buffer[1];
+} __packed;
+
+struct smb2_read_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 17 */
+ __u8 DataOffset;
+ __u8 Reserved;
+ __le32 DataLength;
+ __le32 DataRemaining;
+ __u32 Reserved2;
+ __u8 Buffer[1];
+} __packed;
+
struct smb2_echo_req {
struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 4 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 51e6cd1..f442e46 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -97,6 +97,7 @@ extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le64 *uniqueid);
+extern int smb2_async_readv(struct cifs_readdata *rdata);
extern int SMB2_echo(struct TCP_Server_Info *server);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 24/45] CIFS: Move async write to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (22 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 23/45] CIFS: Add SMB2 support for cifs_iovec_read Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
` (21 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 +++
fs/cifs/cifssmb.c | 4 +++-
fs/cifs/file.c | 13 +++++++++++--
fs/cifs/smb1ops.c | 1 +
4 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 9ce1353..61a013e 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -173,6 +173,7 @@ struct cifs_fattr;
struct smb_vol;
struct cifs_fid;
struct cifs_readdata;
+struct cifs_writedata;
struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -283,6 +284,8 @@ struct smb_version_operations {
int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
/* async read from the server */
int (*async_readv)(struct cifs_readdata *);
+ /* async write to the server */
+ int (*async_writev)(struct cifs_writedata *);
};
struct smb_version_values {
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index e37801c..715781a 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1921,6 +1921,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
{
int i, rc;
struct inode *inode = wdata->cfile->dentry->d_inode;
+ struct TCP_Server_Info *server;
for (i = 0; i < wdata->nr_pages; i++) {
lock_page(wdata->pages[i]);
@@ -1928,7 +1929,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
}
do {
- rc = cifs_async_writev(wdata);
+ server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+ rc = server->ops->async_writev(wdata);
} while (rc == -EAGAIN);
for (i = 0; i < wdata->nr_pages; i++) {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 81403ad..fd2c8bb 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1747,6 +1747,7 @@ static int cifs_writepages(struct address_space *mapping,
bool done = false, scanned = false, range_whole = false;
pgoff_t end, index;
struct cifs_writedata *wdata;
+ struct TCP_Server_Info *server;
struct page *page;
int rc = 0;
@@ -1897,7 +1898,8 @@ retry:
break;
}
wdata->pid = wdata->cfile->pid;
- rc = cifs_async_writev(wdata);
+ server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+ rc = server->ops->async_writev(wdata);
} while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
for (i = 0; i < nr_pages; ++i)
@@ -2228,6 +2230,9 @@ static int
cifs_uncached_retry_writev(struct cifs_writedata *wdata)
{
int rc;
+ struct TCP_Server_Info *server;
+
+ server = tlink_tcon(wdata->cfile->tlink)->ses->server;
do {
if (wdata->cfile->invalidHandle) {
@@ -2235,7 +2240,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
if (rc != 0)
continue;
}
- rc = cifs_async_writev(wdata);
+ rc = server->ops->async_writev(wdata);
} while (rc == -EAGAIN);
return rc;
@@ -2270,6 +2275,10 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
open_file = file->private_data;
tcon = tlink_tcon(open_file->tlink);
+
+ if (!tcon->ses->server->ops->async_writev)
+ return -ENOSYS;
+
offset = *poffset;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index e2dbd22..50c3697 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -786,6 +786,7 @@ struct smb_version_operations smb1_operations = {
.close = cifs_close_file,
.flush = cifs_flush_file,
.async_readv = cifs_async_readv,
+ .async_writev = cifs_async_writev,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (23 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 24/45] CIFS: Move async write to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 26/45] CIFS: Move readpage code to ops struct Pavel Shilovsky
` (20 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsfs.c | 2 +
fs/cifs/cifsglob.h | 47 +++++++++++++++++++
fs/cifs/cifsproto.h | 18 -------
fs/cifs/cifssmb.c | 26 -----------
fs/cifs/smb2ops.c | 1 +
fs/cifs/smb2pdu.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 30 ++++++++++++
fs/cifs/smb2proto.h | 1 +
8 files changed, 204 insertions(+), 44 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 54d8b13..65f8b05 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -89,6 +89,8 @@ extern mempool_t *cifs_mid_poolp;
struct workqueue_struct *cifsiod_wq;
+DEFINE_MUTEX(cifs_kmap_mutex);
+
static int
cifs_read_super(struct super_block *sb)
{
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 61a013e..68eda60 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -582,6 +582,33 @@ get_next_mid(struct TCP_Server_Info *server)
#define CIFS_KMAP_SIZE_LIMIT (1<<24)
#endif /* CONFIG_HIGHMEM */
+#ifdef CONFIG_HIGHMEM
+/*
+ * On arches that have high memory, kmap address space is limited. By
+ * serializing the kmap operations on those arches, we ensure that we don't
+ * end up with a bunch of threads in writeback with partially mapped page
+ * arrays, stuck waiting for kmap to come back. That situation prevents
+ * progress and can deadlock.
+ */
+
+extern struct mutex cifs_kmap_mutex;
+
+static inline void
+cifs_kmap_lock(void)
+{
+ mutex_lock(&cifs_kmap_mutex);
+}
+
+static inline void
+cifs_kmap_unlock(void)
+{
+ mutex_unlock(&cifs_kmap_mutex);
+}
+#else /* !CONFIG_HIGHMEM */
+#define cifs_kmap_lock() do { ; } while (0)
+#define cifs_kmap_unlock() do { ; } while (0)
+#endif /* CONFIG_HIGHMEM */
+
/*
* Macros to allow the TCP_Server_Info->net field and related code to drop out
* when CONFIG_NET_NS isn't set.
@@ -891,6 +918,26 @@ struct cifs_readdata {
struct kvec iov[1];
};
+struct cifs_writedata;
+
+/* asynchronous write support */
+struct cifs_writedata {
+ struct kref refcount;
+ struct list_head list;
+ struct completion done;
+ enum writeback_sync_modes sync_mode;
+ struct work_struct work;
+ struct cifsFileInfo *cfile;
+ __u64 offset;
+ pid_t pid;
+ unsigned int bytes;
+ int result;
+ void (*marshal_iov) (struct kvec *iov,
+ struct cifs_writedata *wdata);
+ unsigned int nr_pages;
+ struct page *pages[1];
+};
+
/*
* Take a reference on the file private data. Must be called with
* cifs_file_list_lock held.
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 949be72..01d5514 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -467,24 +467,6 @@ void cifs_readdata_release(struct kref *refcount);
int cifs_async_readv(struct cifs_readdata *rdata);
int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
-/* asynchronous write support */
-struct cifs_writedata {
- struct kref refcount;
- struct list_head list;
- struct completion done;
- enum writeback_sync_modes sync_mode;
- struct work_struct work;
- struct cifsFileInfo *cfile;
- __u64 offset;
- pid_t pid;
- unsigned int bytes;
- int result;
- void (*marshal_iov) (struct kvec *iov,
- struct cifs_writedata *wdata);
- unsigned int nr_pages;
- struct page *pages[1];
-};
-
int cifs_async_writev(struct cifs_writedata *wdata);
void cifs_writev_complete(struct work_struct *work);
struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 715781a..d27c8be 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -86,32 +86,6 @@ static struct {
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
#endif /* CIFS_POSIX */
-#ifdef CONFIG_HIGHMEM
-/*
- * On arches that have high memory, kmap address space is limited. By
- * serializing the kmap operations on those arches, we ensure that we don't
- * end up with a bunch of threads in writeback with partially mapped page
- * arrays, stuck waiting for kmap to come back. That situation prevents
- * progress and can deadlock.
- */
-static DEFINE_MUTEX(cifs_kmap_mutex);
-
-static inline void
-cifs_kmap_lock(void)
-{
- mutex_lock(&cifs_kmap_mutex);
-}
-
-static inline void
-cifs_kmap_unlock(void)
-{
- mutex_unlock(&cifs_kmap_mutex);
-}
-#else /* !CONFIG_HIGHMEM */
-#define cifs_kmap_lock() do { ; } while(0)
-#define cifs_kmap_unlock() do { ; } while(0)
-#endif /* CONFIG_HIGHMEM */
-
/*
* Mark as invalid, all open files on tree connections since they
* were closed when session to server was lost.
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index ba4adf2..74e8bce 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -425,6 +425,7 @@ struct smb_version_operations smb21_operations = {
.close = smb2_close_file,
.flush = smb2_flush_file,
.async_readv = smb2_async_readv,
+ .async_writev = smb2_async_writev,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 69646ac..c998fbe 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -33,6 +33,7 @@
#include <linux/vfs.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/uaccess.h>
+#include <linux/pagemap.h>
#include <linux/xattr.h>
#include "smb2pdu.h"
#include "cifsglob.h"
@@ -1326,3 +1327,125 @@ smb2_async_readv(struct cifs_readdata *rdata)
cifs_small_buf_release(buf);
return rc;
}
+
+/*
+ * Check the mid_state and signature on received buffer (if any), and queue the
+ * workqueue completion task.
+ */
+static void
+smb2_writev_callback(struct mid_q_entry *mid)
+{
+ struct cifs_writedata *wdata = mid->callback_data;
+ struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+ unsigned int written;
+ struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
+ unsigned int credits_received = 1;
+
+ switch (mid->mid_state) {
+ case MID_RESPONSE_RECEIVED:
+ credits_received = le16_to_cpu(rsp->hdr.CreditRequest);
+ wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
+ if (wdata->result != 0)
+ break;
+
+ written = le32_to_cpu(rsp->DataLength);
+ /*
+ * Mask off high 16 bits when bytes written as returned
+ * by the server is greater than bytes requested by the
+ * client. OS/2 servers are known to set incorrect
+ * CountHigh values.
+ */
+ if (written > wdata->bytes)
+ written &= 0xFFFF;
+
+ if (written < wdata->bytes)
+ wdata->result = -ENOSPC;
+ else
+ wdata->bytes = written;
+ break;
+ case MID_REQUEST_SUBMITTED:
+ case MID_RETRY_NEEDED:
+ wdata->result = -EAGAIN;
+ break;
+ default:
+ wdata->result = -EIO;
+ break;
+ }
+
+ if (wdata->result)
+ cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+
+ queue_work(cifsiod_wq, &wdata->work);
+ DeleteMidQEntry(mid);
+ add_credits(tcon->ses->server, credits_received, 0);
+}
+
+/* smb2_async_writev - send an async write, and set up mid to handle result */
+int
+smb2_async_writev(struct cifs_writedata *wdata)
+{
+ int i, rc = -EACCES;
+ struct smb2_write_req *req = NULL;
+ struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+ struct kvec *iov = NULL;
+
+ rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
+ if (rc)
+ goto async_writev_out;
+
+ /* 1 iov per page + 1 for header */
+ iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
+ if (iov == NULL) {
+ rc = -ENOMEM;
+ goto async_writev_out;
+ }
+
+ req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+
+ req->PersistentFileId = wdata->cfile->fid.persistent_fid;
+ req->VolatileFileId = wdata->cfile->fid.volatile_fid;
+ req->WriteChannelInfoOffset = 0;
+ req->WriteChannelInfoLength = 0;
+ req->Channel = 0;
+ req->Offset = cpu_to_le64(wdata->offset);
+ /* 4 for rfc1002 length field */
+ req->DataOffset = cpu_to_le16(
+ offsetof(struct smb2_write_req, Buffer) - 4);
+ req->RemainingBytes = 0;
+
+ /* 4 for rfc1002 length field and 1 for Buffer */
+ iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+ iov[0].iov_base = (char *)req;
+
+ /*
+ * This function should marshal up the page array into the kvec
+ * array, reserving [0] for the header. It should kmap the pages
+ * and set the iov_len properly for each one. It may also set
+ * wdata->bytes too.
+ */
+ cifs_kmap_lock();
+ wdata->marshal_iov(iov, wdata);
+ cifs_kmap_unlock();
+
+ cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
+
+ req->Length = cpu_to_le32(wdata->bytes);
+
+ inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
+
+ kref_get(&wdata->refcount);
+ rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
+ NULL, smb2_writev_callback, wdata, 0);
+
+ if (rc)
+ kref_put(&wdata->refcount, cifs_writedata_release);
+
+ /* send is done, unmap pages */
+ for (i = 0; i < wdata->nr_pages; i++)
+ kunmap(wdata->pages[i]);
+
+async_writev_out:
+ cifs_small_buf_release(req);
+ kfree(iov);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index d73367c..4712273 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -494,6 +494,36 @@ struct smb2_read_rsp {
__u8 Buffer[1];
} __packed;
+/* For write request Flags field below the following flag is defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+struct smb2_write_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 49 */
+ __le16 DataOffset; /* offset from start of SMB2 header to write data */
+ __le32 Length;
+ __le64 Offset;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ __le32 Channel; /* Reserved MBZ */
+ __le32 RemainingBytes;
+ __le16 WriteChannelInfoOffset; /* Reserved MBZ */
+ __le16 WriteChannelInfoLength; /* Reserved MBZ */
+ __le32 Flags;
+ __u8 Buffer[1];
+} __packed;
+
+struct smb2_write_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 17 */
+ __u8 DataOffset;
+ __u8 Reserved;
+ __le32 DataLength;
+ __le32 DataRemaining;
+ __u32 Reserved2;
+ __u8 Buffer[1];
+} __packed;
+
struct smb2_echo_req {
struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 4 */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index f442e46..ec983be 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -98,6 +98,7 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le64 *uniqueid);
extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int smb2_async_writev(struct cifs_writedata *wdata);
extern int SMB2_echo(struct TCP_Server_Info *server);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 26/45] CIFS: Move readpage code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (24 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 25/45] CIFS: Add SMB2 support for cifs_iovec_write Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 27/45] CIFS: Add readpage support for SMB2 Pavel Shilovsky
` (19 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 5 +++++
fs/cifs/file.c | 28 +++++++++++++++++-----------
fs/cifs/smb1ops.c | 10 ++++++++++
3 files changed, 32 insertions(+), 11 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 68eda60..222d865 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -174,6 +174,7 @@ struct smb_vol;
struct cifs_fid;
struct cifs_readdata;
struct cifs_writedata;
+struct cifs_io_parms;
struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -286,6 +287,10 @@ struct smb_version_operations {
int (*async_readv)(struct cifs_readdata *);
/* async write to the server */
int (*async_writev)(struct cifs_writedata *);
+ /* sync read from the server */
+ int (*sync_read)(const unsigned int, struct cifsFileInfo *,
+ struct cifs_io_parms *, unsigned int *, char **,
+ int *);
};
struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index fd2c8bb..6b92bbe 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2771,8 +2771,8 @@ ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
return cifs_user_readv(iocb, iov, nr_segs, pos);
}
-static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
- loff_t *poffset)
+static ssize_t
+cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
{
int rc = -EACCES;
unsigned int bytes_read = 0;
@@ -2781,8 +2781,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
unsigned int rsize;
struct cifs_sb_info *cifs_sb;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
unsigned int xid;
- char *current_offset;
+ char *cur_offset;
struct cifsFileInfo *open_file;
struct cifs_io_parms io_parms;
int buf_type = CIFS_NO_BUFFER;
@@ -2801,6 +2802,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
}
open_file = file->private_data;
tcon = tlink_tcon(open_file->tlink);
+ server = tcon->ses->server;
+
+ if (!server->ops->sync_read) {
+ free_xid(xid);
+ return -ENOSYS;
+ }
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
pid = open_file->pid;
@@ -2810,9 +2817,8 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, "attempting read on write only file instance");
- for (total_read = 0, current_offset = read_data;
- read_size > total_read;
- total_read += bytes_read, current_offset += bytes_read) {
+ for (total_read = 0, cur_offset = read_data; read_size > total_read;
+ total_read += bytes_read, cur_offset += bytes_read) {
current_read_size = min_t(uint, read_size - total_read, rsize);
/*
* For windows me and 9x we do not want to request more than it
@@ -2830,13 +2836,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
if (rc != 0)
break;
}
- io_parms.netfid = open_file->fid.netfid;
io_parms.pid = pid;
io_parms.tcon = tcon;
- io_parms.offset = *poffset;
+ io_parms.offset = *offset;
io_parms.length = current_read_size;
- rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
- ¤t_offset, &buf_type);
+ rc = server->ops->sync_read(xid, open_file, &io_parms,
+ &bytes_read, &cur_offset,
+ &buf_type);
}
if (rc || (bytes_read == 0)) {
if (total_read) {
@@ -2847,7 +2853,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
}
} else {
cifs_stats_bytes_read(tcon, total_read);
- *poffset += bytes_read;
+ *offset += bytes_read;
}
}
free_xid(xid);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 50c3697..cea958e 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -739,6 +739,15 @@ cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
return CIFSSMBFlush(xid, tcon, fid->netfid);
}
+static int
+cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *bytes_read,
+ char **buf, int *buf_type)
+{
+ parms->netfid = cfile->fid.netfid;
+ return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -787,6 +796,7 @@ struct smb_version_operations smb1_operations = {
.flush = cifs_flush_file,
.async_readv = cifs_async_readv,
.async_writev = cifs_async_writev,
+ .sync_read = cifs_sync_read,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 27/45] CIFS: Add readpage support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (25 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 26/45] CIFS: Move readpage code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 28/45] CIFS: Move writepage to ops struct Pavel Shilovsky
` (18 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2ops.c | 12 ++++++++++++
fs/cifs/smb2pdu.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 2 ++
3 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 74e8bce..4dca13d 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -384,6 +384,17 @@ smb2_read_data_length(char *buf)
return le32_to_cpu(rsp->DataLength);
}
+
+static int
+smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *bytes_read,
+ char **buf, int *buf_type)
+{
+ parms->persistent_fid = cfile->fid.persistent_fid;
+ parms->volatile_fid = cfile->fid.volatile_fid;
+ return SMB2_read(xid, parms, bytes_read, buf, buf_type);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -426,6 +437,7 @@ struct smb_version_operations smb21_operations = {
.flush = smb2_flush_file,
.async_readv = smb2_async_readv,
.async_writev = smb2_async_writev,
+ .sync_read = smb2_sync_read,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index c998fbe..15b9b08 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1328,6 +1328,57 @@ smb2_async_readv(struct cifs_readdata *rdata)
return rc;
}
+int
+SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, char **buf, int *buf_type)
+{
+ int resp_buftype, rc = -EACCES;
+ struct smb2_read_rsp *rsp = NULL;
+ struct kvec iov[1];
+
+ *nbytes = 0;
+ rc = smb2_new_read_req(iov, io_parms, 0, 0);
+ if (rc)
+ return rc;
+
+ rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
+ &resp_buftype, CIFS_LOG_ERROR);
+
+ rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+
+ if (rsp->hdr.Status == STATUS_END_OF_FILE) {
+ free_rsp_buf(resp_buftype, iov[0].iov_base);
+ return 0;
+ }
+
+ if (rc) {
+ cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+ cERROR(1, "Send error in read = %d", rc);
+ } else {
+ *nbytes = le32_to_cpu(rsp->DataLength);
+ if ((*nbytes > CIFS_MAX_MSGSIZE) ||
+ (*nbytes > io_parms->length)) {
+ cFYI(1, "bad length %d for count %d", *nbytes,
+ io_parms->length);
+ rc = -EIO;
+ *nbytes = 0;
+ }
+ }
+
+ if (*buf) {
+ memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset,
+ *nbytes);
+ free_rsp_buf(resp_buftype, iov[0].iov_base);
+ } else if (resp_buftype != CIFS_NO_BUFFER) {
+ *buf = iov[0].iov_base;
+ if (resp_buftype == CIFS_SMALL_BUFFER)
+ *buf_type = CIFS_SMALL_BUFFER;
+ else if (resp_buftype == CIFS_LARGE_BUFFER)
+ *buf_type = CIFS_LARGE_BUFFER;
+ }
+ return rc;
+}
+
/*
* Check the mid_state and signature on received buffer (if any), and queue the
* workqueue completion task.
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index ec983be..97e62f3 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -98,6 +98,8 @@ extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le64 *uniqueid);
extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, char **buf, int *buf_type);
extern int smb2_async_writev(struct cifs_writedata *wdata);
extern int SMB2_echo(struct TCP_Server_Info *server);
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 28/45] CIFS: Move writepage to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (26 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 27/45] CIFS: Add readpage support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 29/45] CIFS: Add writepage support for SMB2 Pavel Shilovsky
` (17 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 4 ++++
fs/cifs/cifsproto.h | 3 +--
fs/cifs/cifssmb.c | 6 ++----
fs/cifs/file.c | 36 ++++++++++++++++++++----------------
fs/cifs/smb1ops.c | 11 +++++++++++
5 files changed, 38 insertions(+), 22 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 222d865..3e54b19 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -291,6 +291,10 @@ struct smb_version_operations {
int (*sync_read)(const unsigned int, struct cifsFileInfo *,
struct cifs_io_parms *, unsigned int *, char **,
int *);
+ /* sync write to the server */
+ int (*sync_write)(const unsigned int, struct cifsFileInfo *,
+ struct cifs_io_parms *, unsigned int *, struct kvec *,
+ unsigned long);
};
struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 01d5514..bdf8948 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -369,8 +369,7 @@ extern int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, const char *buf,
const char __user *ubuf, const int long_op);
extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, struct kvec *iov, const int nvec,
- const int long_op);
+ unsigned int *nbytes, struct kvec *iov, const int nvec);
extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
const char *search_name, __u64 *inode_number,
const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index d27c8be..666535c 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2118,8 +2118,7 @@ async_writev_out:
int
CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
- unsigned int *nbytes, struct kvec *iov, int n_vec,
- const int long_op)
+ unsigned int *nbytes, struct kvec *iov, int n_vec)
{
int rc = -EACCES;
WRITE_REQ *pSMB = NULL;
@@ -2190,8 +2189,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
iov[0].iov_len = smb_hdr_len + 8;
- rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
- long_op);
+ rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
if (rc) {
cFYI(1, "Send error Write2 = %d", rc);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6b92bbe..2ffee05 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1470,15 +1470,16 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
cifsi->server_eof = end_of_write;
}
-static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
- const char *write_data, size_t write_size,
- loff_t *poffset)
+static ssize_t
+cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
+ size_t write_size, loff_t *offset)
{
int rc = 0;
unsigned int bytes_written = 0;
unsigned int total_written;
struct cifs_sb_info *cifs_sb;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
unsigned int xid;
struct dentry *dentry = open_file->dentry;
struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
@@ -1487,9 +1488,13 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
cifs_sb = CIFS_SB(dentry->d_sb);
cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
- *poffset, dentry->d_name.name);
+ *offset, dentry->d_name.name);
+
+ tcon = tlink_tcon(open_file->tlink);
+ server = tcon->ses->server;
- pTcon = tlink_tcon(open_file->tlink);
+ if (!server->ops->sync_write)
+ return -ENOSYS;
xid = get_xid();
@@ -1515,13 +1520,12 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
/* iov[0] is reserved for smb header */
iov[1].iov_base = (char *)write_data + total_written;
iov[1].iov_len = len;
- io_parms.netfid = open_file->fid.netfid;
io_parms.pid = pid;
- io_parms.tcon = pTcon;
- io_parms.offset = *poffset;
+ io_parms.tcon = tcon;
+ io_parms.offset = *offset;
io_parms.length = len;
- rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
- 1, 0);
+ rc = server->ops->sync_write(xid, open_file, &io_parms,
+ &bytes_written, iov, 1);
}
if (rc || (bytes_written == 0)) {
if (total_written)
@@ -1532,18 +1536,18 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
}
} else {
spin_lock(&dentry->d_inode->i_lock);
- cifs_update_eof(cifsi, *poffset, bytes_written);
+ cifs_update_eof(cifsi, *offset, bytes_written);
spin_unlock(&dentry->d_inode->i_lock);
- *poffset += bytes_written;
+ *offset += bytes_written;
}
}
- cifs_stats_bytes_written(pTcon, total_written);
+ cifs_stats_bytes_written(tcon, total_written);
if (total_written > 0) {
spin_lock(&dentry->d_inode->i_lock);
- if (*poffset > dentry->d_inode->i_size)
- i_size_write(dentry->d_inode, *poffset);
+ if (*offset > dentry->d_inode->i_size)
+ i_size_write(dentry->d_inode, *offset);
spin_unlock(&dentry->d_inode->i_lock);
}
mark_inode_dirty_sync(dentry->d_inode);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index cea958e..aa55c2f 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -748,6 +748,16 @@ cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
}
+static int
+cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *written,
+ struct kvec *iov, unsigned long nr_segs)
+{
+
+ parms->netfid = cfile->fid.netfid;
+ return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -797,6 +807,7 @@ struct smb_version_operations smb1_operations = {
.async_readv = cifs_async_readv,
.async_writev = cifs_async_writev,
.sync_read = cifs_sync_read,
+ .sync_write = cifs_sync_write,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 29/45] CIFS: Add writepage support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (27 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 28/45] CIFS: Move writepage to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 30/45] CIFS: Enable signing in SMB2 Pavel Shilovsky
` (16 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2ops.c | 12 ++++++++++
fs/cifs/smb2pdu.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2proto.h | 2 +
3 files changed, 75 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 4dca13d..82852fc 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -395,6 +395,17 @@ smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
return SMB2_read(xid, parms, bytes_read, buf, buf_type);
}
+static int
+smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+ struct cifs_io_parms *parms, unsigned int *written,
+ struct kvec *iov, unsigned long nr_segs)
+{
+
+ parms->persistent_fid = cfile->fid.persistent_fid;
+ parms->volatile_fid = cfile->fid.volatile_fid;
+ return SMB2_write(xid, parms, written, iov, nr_segs);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -438,6 +449,7 @@ struct smb_version_operations smb21_operations = {
.async_readv = smb2_async_readv,
.async_writev = smb2_async_writev,
.sync_read = smb2_sync_read,
+ .sync_write = smb2_sync_write,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 15b9b08..cb7d672 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1500,3 +1500,64 @@ async_writev_out:
kfree(iov);
return rc;
}
+
+/*
+ * SMB2_write function gets iov pointer to kvec array with n_vec as a length.
+ * The length field from io_parms must be at least 1 and indicates a number of
+ * elements with data to write that begins with position 1 in iov array. All
+ * data length is specified by count.
+ */
+int
+SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, struct kvec *iov, int n_vec)
+{
+ int rc = 0;
+ struct smb2_write_req *req = NULL;
+ struct smb2_write_rsp *rsp = NULL;
+ int resp_buftype;
+ *nbytes = 0;
+
+ if (n_vec < 1)
+ return rc;
+
+ rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &req);
+ if (rc)
+ return rc;
+
+ if (io_parms->tcon->ses->server == NULL)
+ return -ECONNABORTED;
+
+ req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+ req->PersistentFileId = io_parms->persistent_fid;
+ req->VolatileFileId = io_parms->volatile_fid;
+ req->WriteChannelInfoOffset = 0;
+ req->WriteChannelInfoLength = 0;
+ req->Channel = 0;
+ req->Length = cpu_to_le32(io_parms->length);
+ req->Offset = cpu_to_le64(io_parms->offset);
+ /* 4 for rfc1002 length field */
+ req->DataOffset = cpu_to_le16(
+ offsetof(struct smb2_write_req, Buffer) - 4);
+ req->RemainingBytes = 0;
+
+ iov[0].iov_base = (char *)req;
+ /* 4 for rfc1002 length field and 1 for Buffer */
+ iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+ /* length of entire message including data to be written */
+ inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
+
+ rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
+ &resp_buftype, 0);
+
+ if (rc) {
+ cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
+ cERROR(1, "Send error in write = %d", rc);
+ } else {
+ rsp = (struct smb2_write_rsp *)iov[0].iov_base;
+ *nbytes = le32_to_cpu(rsp->DataLength);
+ free_rsp_buf(resp_buftype, rsp);
+ }
+ return rc;
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 97e62f3..192d0c7 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -101,6 +101,8 @@ extern int smb2_async_readv(struct cifs_readdata *rdata);
extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, char **buf, int *buf_type);
extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+ unsigned int *nbytes, struct kvec *iov, int n_vec);
extern int SMB2_echo(struct TCP_Server_Info *server);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 30/45] CIFS: Enable signing in SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (28 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 29/45] CIFS: Add writepage support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
[not found] ` <1342626541-29872-31-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
2012-07-18 15:48 ` [PATCH 31/45] CIFS: Move rename to ops struct Pavel Shilovsky
` (15 subsequent siblings)
45 siblings, 1 reply; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Use hmac-sha256 and rather than hmac-md5 that is used for CIFS/SMB.
Signature field in SMB2 header is 16 bytes instead of 8 bytes.
Automatically enable signing by client when requested by the server
when signing ability is available to the client.
Signed-off-by: Shirish Pargaonkar <shirishpargaonkar-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Sachin Prabhu <sprabhu-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/Kconfig | 1 +
fs/cifs/cifsencrypt.c | 30 +++++++++-
fs/cifs/cifsglob.h | 2 +
fs/cifs/cifsproto.h | 1 +
fs/cifs/smb2glob.h | 4 +
fs/cifs/smb2pdu.c | 48 +++++++++++++--
fs/cifs/smb2proto.h | 2 +
fs/cifs/smb2transport.c | 157 ++++++++++++++++++++++++++++++++++++++++++++--
fs/cifs/transport.c | 24 ++++----
9 files changed, 243 insertions(+), 26 deletions(-)
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig
index a08306a..8029301 100644
--- a/fs/cifs/Kconfig
+++ b/fs/cifs/Kconfig
@@ -9,6 +9,7 @@ config CIFS
select CRYPTO_ARC4
select CRYPTO_ECB
select CRYPTO_DES
+ select CRYPTO_SHA256
help
This is the client VFS module for the Common Internet File System
(CIFS) protocol which is the successor to the Server Message Block
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index 63c460e..e572d55 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -686,12 +686,17 @@ calc_seckey(struct cifs_ses *ses)
void
cifs_crypto_shash_release(struct TCP_Server_Info *server)
{
+ if (server->secmech.hmacsha256)
+ crypto_free_shash(server->secmech.hmacsha256);
+
if (server->secmech.md5)
crypto_free_shash(server->secmech.md5);
if (server->secmech.hmacmd5)
crypto_free_shash(server->secmech.hmacmd5);
+ kfree(server->secmech.sdeschmacsha256);
+
kfree(server->secmech.sdeschmacmd5);
kfree(server->secmech.sdescmd5);
@@ -716,6 +721,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
goto crypto_allocate_md5_fail;
}
+ server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
+ if (IS_ERR(server->secmech.hmacsha256)) {
+ cERROR(1, "could not allocate crypto hmacsha256\n");
+ rc = PTR_ERR(server->secmech.hmacsha256);
+ goto crypto_allocate_hmacsha256_fail;
+ }
+
size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.hmacmd5);
server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -727,7 +739,6 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
server->secmech.sdeschmacmd5->shash.flags = 0x0;
-
size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.md5);
server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
@@ -739,12 +750,29 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
server->secmech.sdescmd5->shash.flags = 0x0;
+ size = sizeof(struct shash_desc) +
+ crypto_shash_descsize(server->secmech.hmacsha256);
+ server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
+ if (!server->secmech.sdeschmacsha256) {
+ cERROR(1, "%s: Can't alloc hmacsha256\n", __func__);
+ rc = -ENOMEM;
+ goto crypto_allocate_hmacsha256_sdesc_fail;
+ }
+ server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
+ server->secmech.sdeschmacsha256->shash.flags = 0x0;
+
return 0;
+crypto_allocate_hmacsha256_sdesc_fail:
+ kfree(server->secmech.sdescmd5);
+
crypto_allocate_md5_sdesc_fail:
kfree(server->secmech.sdeschmacmd5);
crypto_allocate_hmacmd5_sdesc_fail:
+ crypto_free_shash(server->secmech.hmacsha256);
+
+crypto_allocate_hmacsha256_fail:
crypto_free_shash(server->secmech.md5);
crypto_allocate_md5_fail:
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3e54b19..78ce424 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -128,8 +128,10 @@ struct sdesc {
struct cifs_secmech {
struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
struct crypto_shash *md5; /* md5 hash function */
+ struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
struct sdesc *sdeschmacmd5; /* ctxt to generate ntlmv2 hash, CR1 */
struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
+ struct sdesc *sdeschmacsha256; /* ctxt to generate smb2 signature */
};
/* per smb session structure/fields */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index bdf8948..722dba8 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -65,6 +65,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
struct TCP_Server_Info *server);
extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern void cifs_delete_mid(struct mid_q_entry *mid);
extern void cifs_wake_up_task(struct mid_q_entry *mid);
extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
unsigned int nvec, mid_receive_t *receive,
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 11505d7..8635574 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -47,4 +47,8 @@
#define END_OF_CHAIN 4
#define RELATED_REQUEST 8
+#define SMB2_SIGNATURE_SIZE (16)
+#define SMB2_NTLMV2_SESSKEY_SIZE (16)
+#define SMB2_HMACSHA256_SIZE (32)
+
#endif /* _SMB2_GLOB_H */
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index cb7d672..46829c6 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -118,9 +118,9 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
/* BB how does SMB2 do case sensitive? */
/* if (tcon->nocase)
hdr->Flags |= SMBFLG_CASELESS; */
- /* if (tcon->ses && tcon->ses->server &&
+ if (tcon->ses && tcon->ses->server &&
(tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
- hdr->Flags |= SMB2_FLAGS_SIGNED; */
+ hdr->Flags |= SMB2_FLAGS_SIGNED;
out:
pdu->StructureSize2 = cpu_to_le16(parmsize);
return;
@@ -441,6 +441,38 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
rc = -EIO;
goto neg_exit;
}
+
+ cFYI(1, "sec_flags 0x%x", sec_flags);
+ if (sec_flags & CIFSSEC_MUST_SIGN) {
+ cFYI(1, "Signing required");
+ if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED |
+ SMB2_NEGOTIATE_SIGNING_ENABLED))) {
+ cERROR(1, "signing required but server lacks support");
+ rc = -EOPNOTSUPP;
+ goto neg_exit;
+ }
+ server->sec_mode |= SECMODE_SIGN_REQUIRED;
+ } else if (sec_flags & CIFSSEC_MAY_SIGN) {
+ cFYI(1, "Signing optional");
+ if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+ cFYI(1, "Server requires signing");
+ server->sec_mode |= SECMODE_SIGN_REQUIRED;
+ } else {
+ server->sec_mode &=
+ ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+ }
+ } else {
+ cFYI(1, "Signing disabled");
+ if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+ cERROR(1, "Server requires packet signing to be enabled"
+ " in /proc/fs/cifs/SecurityFlags.");
+ rc = -EOPNOTSUPP;
+ goto neg_exit;
+ }
+ server->sec_mode &=
+ ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+ }
+
#ifdef CONFIG_SMB2_ASN1 /* BB REMOVEME when updated asn1.c ready */
rc = decode_neg_token_init(security_blob, blob_length,
&server->sec_type);
@@ -669,6 +701,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
/* since no tcon, smb2_init can not do this, so do here */
req->hdr.SessionId = ses->Suid;
+ if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+ req->hdr.Flags |= SMB2_FLAGS_SIGNED;
rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
/*
@@ -1268,10 +1302,12 @@ smb2_readv_callback(struct mid_q_entry *mid)
case MID_RESPONSE_RECEIVED:
credits_received = le16_to_cpu(buf->CreditRequest);
/* result already set, check signature */
- /* if (server->sec_mode &
- (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- if (smb2_verify_signature(mid->resp_buf, server))
- cERROR(1, "Unexpected SMB signature"); */
+ if (server->sec_mode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+ if (smb2_verify_signature2(rdata->iov, rdata->nr_iov,
+ server))
+ cERROR(1, "Unexpected SMB signature");
+ }
/* FIXME: should this be counted toward the initiating task? */
task_io_account_read(rdata->bytes);
cifs_stats_bytes_read(tcon, rdata->bytes);
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 192d0c7..dbbdc39 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -39,6 +39,8 @@ extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
extern __le16 *cifs_convert_path_to_utf16(const char *from,
struct cifs_sb_info *cifs_sb);
+extern int smb2_verify_signature2(struct kvec *, unsigned int,
+ struct TCP_Server_Info *);
extern int smb2_check_receive(struct mid_q_entry *mid,
struct TCP_Server_Info *server, bool log_error);
extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c
index 31f5d42..7276f6f 100644
--- a/fs/cifs/smb2transport.c
+++ b/fs/cifs/smb2transport.c
@@ -36,6 +36,149 @@
#include "smb2proto.h"
#include "cifs_debug.h"
#include "smb2status.h"
+#include "smb2glob.h"
+
+static int
+smb2_calc_signature2(const struct kvec *iov, int n_vec,
+ struct TCP_Server_Info *server)
+{
+ int i, rc;
+ unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
+ unsigned char *sigptr = smb2_signature;
+ struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+ memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
+ memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+
+ rc = crypto_shash_setkey(server->secmech.hmacsha256,
+ server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+ if (rc) {
+ cERROR(1, "%s: Could not update with response\n", __func__);
+ return rc;
+ }
+
+ rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+ if (rc) {
+ cERROR(1, "%s: Could not init md5\n", __func__);
+ return rc;
+ }
+
+ for (i = 0; i < n_vec; i++) {
+ if (iov[i].iov_len == 0)
+ continue;
+ if (iov[i].iov_base == NULL) {
+ cERROR(1, "null iovec entry");
+ return -EIO;
+ }
+ /*
+ * The first entry includes a length field (which does not get
+ * signed that occupies the first 4 bytes before the header).
+ */
+ if (i == 0) {
+ if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
+ break; /* nothing to sign or corrupt header */
+ rc =
+ crypto_shash_update(
+ &server->secmech.sdeschmacsha256->shash,
+ iov[i].iov_base + 4, iov[i].iov_len - 4);
+ } else {
+ rc =
+ crypto_shash_update(
+ &server->secmech.sdeschmacsha256->shash,
+ iov[i].iov_base, iov[i].iov_len);
+ }
+ if (rc) {
+ cERROR(1, "%s: Could not update with payload\n",
+ __func__);
+ return rc;
+ }
+ }
+
+ rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+ sigptr);
+ if (rc)
+ cERROR(1, "%s: Could not generate sha256 hash\n", __func__);
+
+ memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+
+ return rc;
+}
+
+/* must be called with server->srv_mutex held */
+static int
+smb2_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server)
+{
+ int rc = 0;
+ struct smb2_hdr *smb2_pdu = iov[0].iov_base;
+
+ if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
+ server->tcpStatus == CifsNeedNegotiate)
+ return rc;
+
+ if (!server->session_estab) {
+ strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
+ return rc;
+ }
+
+ rc = smb2_calc_signature2(iov, n_vec, server);
+
+ return rc;
+}
+
+int
+smb2_verify_signature2(struct kvec *iov, unsigned int n_vec,
+ struct TCP_Server_Info *server)
+{
+ unsigned int rc;
+ char server_response_sig[16];
+ struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+ if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
+ (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
+ (!server->session_estab))
+ return 0;
+
+ /*
+ * BB what if signatures are supposed to be on for session but
+ * server does not send one? BB
+ */
+
+ /* Do not need to verify session setups with signature "BSRSPYL " */
+ if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
+ cFYI(1, "dummy signature received for smb command 0x%x",
+ smb2_pdu->Command);
+
+ /*
+ * Save off the origiginal signature so we can modify the smb and check
+ * our calculated signature against what the server sent.
+ */
+ memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
+
+ memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
+
+ mutex_lock(&server->srv_mutex);
+ rc = smb2_calc_signature2(iov, n_vec, server);
+ mutex_unlock(&server->srv_mutex);
+
+ if (rc)
+ return rc;
+
+ if (memcmp(server_response_sig, smb2_pdu->Signature,
+ SMB2_SIGNATURE_SIZE))
+ return -EACCES;
+ else
+ return 0;
+}
+
+static int
+smb2_verify_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server)
+{
+ struct kvec iov;
+
+ iov.iov_base = (char *)smb2_pdu;
+ iov.iov_len = get_rfc1002_length(smb2_pdu) + 4;
+ return smb2_verify_signature2(&iov, 1, server);
+}
/*
* Set message id for the request. Should be called after wait_for_free_request
@@ -118,12 +261,11 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
dump_smb(mid->resp_buf, min_t(u32, 80, len));
/* convert the length into a more usable form */
- /* BB - uncomment with SMB2 signing implementation */
- /* if ((len > 24) &&
+ if ((len > 24) &&
(server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
if (smb2_verify_signature(mid->resp_buf, server))
cERROR(1, "Unexpected SMB signature");
- } */
+ }
return map_smb2_to_linux_error(mid->resp_buf, log_error);
}
@@ -141,9 +283,9 @@ smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
rc = smb2_get_mid_entry(ses, hdr, &mid);
if (rc)
return rc;
- /* rc = smb2_sign_smb2(iov, nvec, ses->server);
+ rc = smb2_sign_smb2(iov, nvec, ses->server);
if (rc)
- delete_mid(mid); */
+ cifs_delete_mid(mid);
*ret_mid = mid;
return rc;
}
@@ -162,11 +304,12 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
if (mid == NULL)
return -ENOMEM;
- /* rc = smb2_sign_smb2(iov, nvec, server);
+ rc = smb2_sign_smb2(iov, nvec, server);
if (rc) {
DeleteMidQEntry(mid);
return rc;
- }*/
+ }
+
*ret_mid = mid;
return rc;
}
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 4d37902..cb18dbf 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -109,8 +109,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
mempool_free(midEntry, cifs_mid_poolp);
}
-static void
-delete_mid(struct mid_q_entry *mid)
+void
+cifs_delete_mid(struct mid_q_entry *mid)
{
spin_lock(&GlobalMid_Lock);
list_del(&mid->qhead);
@@ -423,7 +423,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
if (rc == 0)
return 0;
- delete_mid(mid);
+ cifs_delete_mid(mid);
add_credits(server, 1, optype);
wake_up(&server->request_q);
return rc;
@@ -533,7 +533,7 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
return rc;
rc = cifs_sign_smb2(iov, nvec, ses->server, &mid->sequence_number);
if (rc)
- delete_mid(mid);
+ cifs_delete_mid(mid);
*ret_mid = mid;
return rc;
}
@@ -653,11 +653,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
rc = ses->server->ops->check_receive(midQ, ses->server,
flags & CIFS_LOG_ERROR);
- /* mark it so buf will not be freed by delete_mid */
+ /* mark it so buf will not be freed by cifs_delete_mid */
if ((flags & CIFS_NO_RESP) == 0)
midQ->resp_buf = NULL;
out:
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
add_credits(ses->server, credits, optype);
return rc;
@@ -763,7 +763,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
rc = cifs_check_receive(midQ, ses->server, 0);
out:
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
add_credits(ses->server, 1, 0);
return rc;
@@ -847,7 +847,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
if (rc) {
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
mutex_unlock(&ses->server->srv_mutex);
return rc;
}
@@ -860,7 +860,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
mutex_unlock(&ses->server->srv_mutex);
if (rc < 0) {
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
return rc;
}
@@ -881,7 +881,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
blocking lock to return. */
rc = send_cancel(ses->server, in_buf, midQ);
if (rc) {
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
return rc;
}
} else {
@@ -893,7 +893,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
/* If we get -ENOLCK back the lock may have
already been removed. Don't exit in this case. */
if (rc && rc != -ENOLCK) {
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
return rc;
}
}
@@ -930,7 +930,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
rc = cifs_check_receive(midQ, ses->server, 0);
out:
- delete_mid(midQ);
+ cifs_delete_mid(midQ);
if (rstart && rc == -EACCES)
return -ERESTARTSYS;
return rc;
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 31/45] CIFS: Move rename to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (29 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 30/45] CIFS: Enable signing in SMB2 Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 32/45] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
` (14 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 ++
fs/cifs/cifsproto.h | 5 +--
fs/cifs/cifssmb.c | 22 +++++++-----
fs/cifs/inode.c | 92 ++++++++++++++++++++++++++------------------------
fs/cifs/smb1ops.c | 1 +
5 files changed, 66 insertions(+), 57 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 78ce424..0f8a466 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -275,6 +275,9 @@ struct smb_version_operations {
/* open, rename and delete file */
int (*rename_pending_delete)(const char *, struct dentry *,
const unsigned int);
+ /* send rename request */
+ int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
+ const char *, struct cifs_sb_info *);
/* open a file for non-posix mounts */
int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 722dba8..ef94f36 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -310,9 +310,8 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb);
extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
int netfid, const char *target_name,
const struct nls_table *nls_codepage,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 666535c..c1a18a6 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2528,8 +2528,8 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
int
CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage, int remap)
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
{
int rc = 0;
RENAME_REQ *pSMB = NULL;
@@ -2537,6 +2537,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
int bytes_returned;
int name_len, name_len2;
__u16 count;
+ int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
cFYI(1, "In CIFSSMBRename");
renameRetry:
@@ -2551,9 +2552,9 @@ renameRetry:
ATTR_DIRECTORY);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len =
- cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
- PATH_MAX, nls_codepage, remap);
+ name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
+ from_name, PATH_MAX,
+ cifs_sb->local_nls, remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0x04; /* pad */
@@ -2561,17 +2562,18 @@ renameRetry:
pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 =
cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
- toName, PATH_MAX, nls_codepage, remap);
+ to_name, PATH_MAX, cifs_sb->local_nls,
+ remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fromName, PATH_MAX);
+ name_len = strnlen(from_name, PATH_MAX);
name_len++; /* trailing null */
- strncpy(pSMB->OldFileName, fromName, name_len);
- name_len2 = strnlen(toName, PATH_MAX);
+ strncpy(pSMB->OldFileName, from_name, name_len);
+ name_len2 = strnlen(to_name, PATH_MAX);
name_len2++; /* trailing null */
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
- strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+ strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
name_len2++; /* trailing null */
name_len2++; /* signature byte */
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 39ef1a6..f1448d9 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1512,29 +1512,32 @@ rmdir_exit:
}
static int
-cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
- const char *fromPath, struct dentry *to_dentry,
- const char *toPath)
+cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+ const char *from_path, struct dentry *to_dentry,
+ const char *to_path)
{
struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
__u16 srcfid;
int oplock, rc;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+
+ if (!server->ops->rename)
+ return -ENOSYS;
/* try path-based rename first */
- rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
/*
- * don't bother with rename by filehandle unless file is busy and
- * source Note that cross directory moves do not work with
+ * Don't bother with rename by filehandle unless file is busy and
+ * source. Note that cross directory moves do not work with
* rename by filehandle to various Windows servers.
*/
if (rc == 0 || rc != -ETXTBSY)
@@ -1545,29 +1548,28 @@ cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
goto do_rename_exit;
/* open the file to be renamed -- we need DELETE perms */
- rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+ rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
CREATE_NOT_DIR, &srcfid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
-
if (rc == 0) {
- rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+ rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
(const char *) to_dentry->d_name.name,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
-
- CIFSSMBClose(xid, pTcon, srcfid);
+ CIFSSMBClose(xid, tcon, srcfid);
}
do_rename_exit:
cifs_put_tlink(tlink);
return rc;
}
-int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
- struct inode *target_dir, struct dentry *target_dentry)
+int
+cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
+ struct inode *target_dir, struct dentry *target_dentry)
{
- char *fromName = NULL;
- char *toName = NULL;
+ char *from_name = NULL;
+ char *to_name = NULL;
struct cifs_sb_info *cifs_sb;
struct tcon_link *tlink;
struct cifs_tcon *tcon;
@@ -1588,25 +1590,25 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
* we already have the rename sem so we do not need to
* grab it again here to protect the path integrity
*/
- fromName = build_path_from_dentry(source_dentry);
- if (fromName == NULL) {
+ from_name = build_path_from_dentry(source_dentry);
+ if (from_name == NULL) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
- toName = build_path_from_dentry(target_dentry);
- if (toName == NULL) {
+ to_name = build_path_from_dentry(target_dentry);
+ if (to_name == NULL) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
- rc = cifs_do_rename(xid, source_dentry, fromName,
- target_dentry, toName);
+ rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+ to_name);
if (rc == -EEXIST && tcon->unix_ext) {
/*
- * Are src and dst hardlinks of same inode? We can
- * only tell with unix extensions enabled
+ * Are src and dst hardlinks of same inode? We can only tell
+ * with unix extensions enabled.
*/
info_buf_source =
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1617,19 +1619,19 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
}
info_buf_target = info_buf_source + 1;
- tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
- info_buf_source,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
+ info_buf_source,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc != 0)
goto unlink_target;
- tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
- info_buf_target,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
+ info_buf_target,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
if (tmprc == 0 && (info_buf_source->UniqueId ==
info_buf_target->UniqueId)) {
@@ -1637,8 +1639,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
rc = 0;
goto cifs_rename_exit;
}
- } /* else ... BB we could add the same check for Windows by
- checking the UniqueId via FILE_INTERNAL_INFO */
+ }
+ /*
+ * else ... BB we could add the same check for Windows by
+ * checking the UniqueId via FILE_INTERNAL_INFO
+ */
unlink_target:
/* Try unlinking the target dentry if it's not negative */
@@ -1646,15 +1651,14 @@ unlink_target:
tmprc = cifs_unlink(target_dir, target_dentry);
if (tmprc)
goto cifs_rename_exit;
-
- rc = cifs_do_rename(xid, source_dentry, fromName,
- target_dentry, toName);
+ rc = cifs_do_rename(xid, source_dentry, from_name,
+ target_dentry, to_name);
}
cifs_rename_exit:
kfree(info_buf_source);
- kfree(fromName);
- kfree(toName);
+ kfree(from_name);
+ kfree(to_name);
free_xid(xid);
cifs_put_tlink(tlink);
return rc;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index aa55c2f..3773920 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -800,6 +800,7 @@ struct smb_version_operations smb1_operations = {
.rmdir = CIFSSMBRmDir,
.unlink = CIFSSMBDelFile,
.rename_pending_delete = cifs_rename_pending_delete,
+ .rename = CIFSSMBRename,
.open = cifs_open_file,
.set_fid = cifs_set_fid,
.close = cifs_close_file,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 32/45] CIFS: Add SMB2 support for rename operation
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (30 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 31/45] CIFS: Move rename to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 33/45] CIFS: Move hardlink to ops struct Pavel Shilovsky
` (13 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/smb2inode.c | 25 ++++++++++++
fs/cifs/smb2ops.c | 1 +
fs/cifs/smb2pdu.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 28 +++++++++++++
fs/cifs/smb2proto.h | 6 +++
5 files changed, 167 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index ee3a1ef..a6952ba 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -74,6 +74,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
* SMB2_open() call.
*/
break;
+ case SMB2_OP_RENAME:
+ tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
+ (__le16 *)data);
+ break;
default:
cERROR(1, "Invalid command");
break;
@@ -170,3 +174,24 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
0, CREATE_DELETE_ON_CLOSE, NULL,
SMB2_OP_DELETE);
}
+
+int
+smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
+{
+ __le16 *smb2_to_name = NULL;
+ int rc;
+
+ smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
+ if (smb2_to_name == NULL) {
+ rc = -ENOMEM;
+ goto smb2_rename_path;
+ }
+
+ rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE,
+ FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME);
+smb2_rename_path:
+ kfree(smb2_to_name);
+ return rc;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 82852fc..da13a60 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -442,6 +442,7 @@ struct smb_version_operations smb21_operations = {
.mkdir_setinfo = smb2_mkdir_setinfo,
.rmdir = smb2_rmdir,
.unlink = smb2_unlink,
+ .rename = smb2_rename_path,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 46829c6..515c141 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1597,3 +1597,110 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
}
return rc;
}
+
+static int
+send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, int info_class,
+ unsigned int num, void **data, unsigned int *size)
+{
+ struct smb2_set_info_req *req;
+ struct smb2_set_info_rsp *rsp = NULL;
+ struct kvec *iov;
+ int rc = 0;
+ int resp_buftype;
+ unsigned int i;
+ struct TCP_Server_Info *server;
+ struct cifs_ses *ses = tcon->ses;
+
+ if (ses && (ses->server))
+ server = ses->server;
+ else
+ return -EIO;
+
+ if (!num)
+ return -EINVAL;
+
+ iov = kmalloc(sizeof(struct kvec) * num, GFP_KERNEL);
+ if (!iov)
+ return -ENOMEM;
+
+ rc = small_smb2_init(SMB2_SET_INFO, tcon, (void **) &req);
+ if (rc) {
+ kfree(iov);
+ return rc;
+ }
+
+ req->InfoType = SMB2_O_INFO_FILE;
+ req->FileInfoClass = info_class;
+ req->PersistentFileId = persistent_fid;
+ req->VolatileFileId = volatile_fid;
+
+ /* 4 for RFC1001 length and 1 for Buffer */
+ req->BufferOffset =
+ cpu_to_le16(sizeof(struct smb2_set_info_req) - 1 - 4);
+ req->BufferLength = cpu_to_le32(*size);
+
+ inc_rfc1001_len(req, *size - 1 /* Buffer */);
+
+ memcpy(req->Buffer, *data, *size);
+
+ iov[0].iov_base = (char *)req;
+ /* 4 for RFC1001 length */
+ iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+ for (i = 1; i < num; i++) {
+ inc_rfc1001_len(req, size[i]);
+ le32_add_cpu(&req->BufferLength, size[i]);
+ iov[i].iov_base = (char *)data[i];
+ iov[i].iov_len = size[i];
+ }
+
+ rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
+ rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
+
+ if (rc != 0) {
+ cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
+ goto out;
+ }
+
+ if (rsp == NULL) {
+ rc = -EIO;
+ goto out;
+ }
+
+out:
+ free_rsp_buf(resp_buftype, rsp);
+ kfree(iov);
+ return rc;
+}
+
+int
+SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+ struct smb2_file_rename_info info;
+ void **data;
+ unsigned int size[2];
+ int rc;
+ int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+ data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ info.ReplaceIfExists = 1; /* 1 = replace existing target with new */
+ /* 0 = fail if target already exists */
+ info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */
+ info.FileNameLength = cpu_to_le32(len);
+
+ data[0] = &info;
+ size[0] = sizeof(struct smb2_file_rename_info);
+
+ data[1] = target_file;
+ size[1] = len + 2 /* null */;
+
+ rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+ FILE_RENAME_INFORMATION, 2, data, size);
+ kfree(data);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 4712273..e2c7887 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -566,6 +566,25 @@ struct smb2_query_info_rsp {
__u8 Buffer[1];
} __packed;
+struct smb2_set_info_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 33 */
+ __u8 InfoType;
+ __u8 FileInfoClass;
+ __le32 BufferLength;
+ __le16 BufferOffset;
+ __u16 Reserved;
+ __le32 AdditionalInformation;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ __u8 Buffer[1];
+} __packed;
+
+struct smb2_set_info_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 2 */
+} __packed;
+
/*
* PDU infolevel structure definitions
* BB consider moving to a different header
@@ -623,6 +642,15 @@ struct smb2_file_internal_info {
__le64 IndexNumber;
} __packed; /* level 6 Query */
+struct smb2_file_rename_info { /* encoding of request for level 10 */
+ __u8 ReplaceIfExists; /* 1 = replace existing target with new */
+ /* 0 = fail if target already exists */
+ __u8 Reserved[7];
+ __u64 RootDirectory; /* MBZ for network operations (why says spec?) */
+ __le32 FileNameLength;
+ char FileName[0]; /* New name to be assigned */
+} __packed; /* level 10 Set */
+
/*
* This level 18, although with struct with same name is different from cifs
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index dbbdc39..b43036e 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -65,6 +65,9 @@ extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb);
extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, int disposition,
@@ -106,5 +109,8 @@ extern int smb2_async_writev(struct cifs_writedata *wdata);
extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec);
extern int SMB2_echo(struct TCP_Server_Info *server);
+extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ __le16 *target_file);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 33/45] CIFS: Move hardlink to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (31 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 32/45] CIFS: Add SMB2 support for rename operation Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
` (12 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 4 +++
fs/cifs/cifsproto.h | 8 ++---
fs/cifs/cifssmb.c | 20 +++++++------
fs/cifs/link.c | 74 ++++++++++++++++++++++++++++++--------------------
fs/cifs/smb1ops.c | 1 +
5 files changed, 63 insertions(+), 44 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0f8a466..de11b1f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -278,6 +278,10 @@ struct smb_version_operations {
/* send rename request */
int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
const char *, struct cifs_sb_info *);
+ /* send create hardlink request */
+ int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
+ const char *, const char *,
+ struct cifs_sb_info *);
/* open a file for non-posix mounts */
int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index ef94f36..06b90bb 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -316,11 +316,9 @@ extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
int netfid, const char *target_name,
const struct nls_table *nls_codepage,
int remap_special_chars);
-extern int CIFSCreateHardLink(const unsigned int xid,
- struct cifs_tcon *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
+extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb);
extern int CIFSUnixCreateHardLink(const unsigned int xid,
struct cifs_tcon *tcon,
const char *fromName, const char *toName,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index c1a18a6..3029bf8 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2921,8 +2921,8 @@ createHardLinkRetry:
int
CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fromName, const char *toName,
- const struct nls_table *nls_codepage, int remap)
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
{
int rc = 0;
NT_RENAME_REQ *pSMB = NULL;
@@ -2930,6 +2930,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
int bytes_returned;
int name_len, name_len2;
__u16 count;
+ int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
cFYI(1, "In CIFSCreateHardLink");
winCreateHardLinkRetry:
@@ -2949,8 +2950,8 @@ winCreateHardLinkRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
- PATH_MAX, nls_codepage, remap);
+ cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
+ PATH_MAX, cifs_sb->local_nls, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -2959,17 +2960,18 @@ winCreateHardLinkRetry:
pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
name_len2 =
cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
- toName, PATH_MAX, nls_codepage, remap);
+ to_name, PATH_MAX, cifs_sb->local_nls,
+ remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fromName, PATH_MAX);
+ name_len = strnlen(from_name, PATH_MAX);
name_len++; /* trailing null */
- strncpy(pSMB->OldFileName, fromName, name_len);
- name_len2 = strnlen(toName, PATH_MAX);
+ strncpy(pSMB->OldFileName, from_name, name_len);
+ name_len2 = strnlen(to_name, PATH_MAX);
name_len2++; /* trailing null */
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
- strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+ strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
name_len2++; /* trailing null */
name_len2++; /* signature byte */
}
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index d08b76c..169fa74 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -391,70 +391,84 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
{
int rc = -EACCES;
unsigned int xid;
- char *fromName = NULL;
- char *toName = NULL;
+ char *from_name = NULL;
+ char *to_name = NULL;
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
struct cifsInodeInfo *cifsInode;
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
+ tcon = tlink_tcon(tlink);
xid = get_xid();
- fromName = build_path_from_dentry(old_file);
- toName = build_path_from_dentry(direntry);
- if ((fromName == NULL) || (toName == NULL)) {
+ from_name = build_path_from_dentry(old_file);
+ to_name = build_path_from_dentry(direntry);
+ if ((from_name == NULL) || (to_name == NULL)) {
rc = -ENOMEM;
goto cifs_hl_exit;
}
- if (pTcon->unix_ext)
- rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
+ if (tcon->unix_ext)
+ rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else {
- rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
+ server = tcon->ses->server;
+ if (!server->ops->create_hardlink)
+ return -ENOSYS;
+ rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
+ cifs_sb);
if ((rc == -EIO) || (rc == -EINVAL))
rc = -EOPNOTSUPP;
}
d_drop(direntry); /* force new lookup from server of target */
- /* if source file is cached (oplocked) revalidate will not go to server
- until the file is closed or oplock broken so update nlinks locally */
+ /*
+ * if source file is cached (oplocked) revalidate will not go to server
+ * until the file is closed or oplock broken so update nlinks locally
+ */
if (old_file->d_inode) {
cifsInode = CIFS_I(old_file->d_inode);
if (rc == 0) {
inc_nlink(old_file->d_inode);
-/* BB should we make this contingent on superblock flag NOATIME? */
-/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
- /* parent dir timestamps will update from srv
- within a second, would it really be worth it
- to set the parent dir cifs inode time to zero
- to force revalidate (faster) for it too? */
+ /*
+ * BB should we make this contingent on superblock flag
+ * NOATIME?
+ */
+ /* old_file->d_inode->i_ctime = CURRENT_TIME; */
+ /*
+ * parent dir timestamps will update from srv within a
+ * second, would it really be worth it to set the parent
+ * dir cifs inode time to zero to force revalidate
+ * (faster) for it too?
+ */
}
- /* if not oplocked will force revalidate to get info
- on source file from srv */
+ /*
+ * if not oplocked will force revalidate to get info on source
+ * file from srv
+ */
cifsInode->time = 0;
- /* Will update parent dir timestamps from srv within a second.
- Would it really be worth it to set the parent dir (cifs
- inode) time field to zero to force revalidate on parent
- directory faster ie
- CIFS_I(inode)->time = 0; */
+ /*
+ * Will update parent dir timestamps from srv within a second.
+ * Would it really be worth it to set the parent dir (cifs
+ * inode) time field to zero to force revalidate on parent
+ * directory faster ie
+ *
+ * CIFS_I(inode)->time = 0;
+ */
}
cifs_hl_exit:
- kfree(fromName);
- kfree(toName);
+ kfree(from_name);
+ kfree(to_name);
free_xid(xid);
cifs_put_tlink(tlink);
return rc;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3773920..e5d6344 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -801,6 +801,7 @@ struct smb_version_operations smb1_operations = {
.unlink = CIFSSMBDelFile,
.rename_pending_delete = cifs_rename_pending_delete,
.rename = CIFSSMBRename,
+ .create_hardlink = CIFSCreateHardLink,
.open = cifs_open_file,
.set_fid = cifs_set_fid,
.close = cifs_close_file,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (32 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 33/45] CIFS: Move hardlink to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 35/45] CIFS: Move set_file_size to ops struct Pavel Shilovsky
` (11 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2glob.h | 1 +
fs/cifs/smb2inode.c | 34 ++++++++++++++++++++++++++++------
fs/cifs/smb2ops.c | 1 +
fs/cifs/smb2pdu.c | 31 +++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 9 +++++++++
fs/cifs/smb2proto.h | 6 ++++++
6 files changed, 76 insertions(+), 6 deletions(-)
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 8635574..21555d8 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -40,6 +40,7 @@
#define SMB2_OP_MKDIR 5
#define SMB2_OP_RENAME 6
#define SMB2_OP_DELETE 7
+#define SMB2_OP_HARDLINK 8
/* Used when constructing chained read requests. */
#define CHAINED_REQUEST 1
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index a6952ba..1921c9c 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -78,6 +78,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
(__le16 *)data);
break;
+ case SMB2_OP_HARDLINK:
+ tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
+ volatile_fid, (__le16 *)data);
+ break;
default:
cERROR(1, "Invalid command");
break;
@@ -175,10 +179,10 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
SMB2_OP_DELETE);
}
-int
-smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
- const char *from_name, const char *to_name,
- struct cifs_sb_info *cifs_sb)
+static int
+smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb, __u32 access, int command)
{
__le16 *smb2_to_name = NULL;
int rc;
@@ -189,9 +193,27 @@ smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
goto smb2_rename_path;
}
- rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, DELETE,
- FILE_OPEN, 0, 0, smb2_to_name, SMB2_OP_RENAME);
+ rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
+ FILE_OPEN, 0, 0, smb2_to_name, command);
smb2_rename_path:
kfree(smb2_to_name);
return rc;
}
+
+int
+smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
+{
+ return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+ DELETE, SMB2_OP_RENAME);
+}
+
+int
+smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb)
+{
+ return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+ FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index da13a60..f9e3a13 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -443,6 +443,7 @@ struct smb_version_operations smb21_operations = {
.rmdir = smb2_rmdir,
.unlink = smb2_unlink,
.rename = smb2_rename_path,
+ .create_hardlink = smb2_create_hardlink,
.open = smb2_open_file,
.set_fid = smb2_set_fid,
.close = smb2_close_file,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 515c141..4d9ef2c 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1704,3 +1704,34 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
kfree(data);
return rc;
}
+
+int
+SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+ struct smb2_file_link_info info;
+ void **data;
+ unsigned int size[2];
+ int rc;
+ int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+ data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ info.ReplaceIfExists = 0; /* 1 = replace existing link with new */
+ /* 0 = fail if link already exists */
+ info.RootDirectory = 0; /* MBZ for network ops (why does spec say?) */
+ info.FileNameLength = cpu_to_le32(len);
+
+ data[0] = &info;
+ size[0] = sizeof(struct smb2_file_link_info);
+
+ data[1] = target_file;
+ size[1] = len + 2 /* null */;
+
+ rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+ FILE_LINK_INFORMATION, 2, data, size);
+ kfree(data);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index e2c7887..34a9329 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -651,6 +651,15 @@ struct smb2_file_rename_info { /* encoding of request for level 10 */
char FileName[0]; /* New name to be assigned */
} __packed; /* level 10 Set */
+struct smb2_file_link_info { /* encoding of request for level 11 */
+ __u8 ReplaceIfExists; /* 1 = replace existing link with new */
+ /* 0 = fail if link already exists */
+ __u8 Reserved[7];
+ __u64 RootDirectory; /* MBZ for network operations (why says spec?) */
+ __le32 FileNameLength;
+ char FileName[0]; /* Name to be assigned to new link */
+} __packed; /* level 11 Set */
+
/*
* This level 18, although with struct with same name is different from cifs
* level 0x107. Level 0x107 has an extra u64 between AccessFlags and
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index b43036e..99f6945 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -68,6 +68,9 @@ extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
const char *from_name, const char *to_name,
struct cifs_sb_info *cifs_sb);
+extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *from_name, const char *to_name,
+ struct cifs_sb_info *cifs_sb);
extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, int disposition,
@@ -112,5 +115,8 @@ extern int SMB2_echo(struct TCP_Server_Info *server);
extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le16 *target_file);
+extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ __le16 *target_file);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 35/45] CIFS: Move set_file_size to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (33 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 34/45] CIFS: Add SMB2 support for hardlink operation Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 36/45] CIFS: Add SMB2 support for set_file_size Pavel Shilovsky
` (10 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 6 +++
fs/cifs/cifsproto.h | 10 ++---
fs/cifs/cifssmb.c | 40 ++++++++++---------
fs/cifs/inode.c | 106 +++++++++++++++++++++++++++------------------------
fs/cifs/smb1ops.c | 2 +
5 files changed, 89 insertions(+), 75 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index de11b1f..3f7a53d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -252,6 +252,12 @@ struct smb_version_operations {
int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *,
u64 *uniqueid, FILE_ALL_INFO *);
+ /* set size by path */
+ int (*set_path_size)(const unsigned int, struct cifs_tcon *,
+ const char *, __u64, struct cifs_sb_info *, bool);
+ /* set size by file handle */
+ int (*set_file_size)(const unsigned int, struct cifs_tcon *,
+ struct cifsFileInfo *, __u64, bool);
/* build a full path to the root of the mount */
char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *,
struct cifs_tcon *);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 06b90bb..6e04941 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -270,13 +270,11 @@ extern int CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon,
const struct nls_table *nls_codepage);
#endif /* possibly unneeded function */
extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, __u64 size,
- bool setAllocationSizeFlag,
- const struct nls_table *nls_codepage,
- int remap_special_chars);
+ const char *file_name, __u64 size,
+ struct cifs_sb_info *cifs_sb, bool set_allocation);
extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
- __u64 size, __u16 fileHandle, __u32 opener_pid,
- bool AllocSizeFlag);
+ struct cifsFileInfo *cfile, __u64 size,
+ bool set_allocation);
struct cifs_unix_set_info_args {
__u64 ctime;
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 3029bf8..875a8c2 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -5392,16 +5392,16 @@ QFSPosixRetry:
}
-/* We can not use write of zero bytes trick to
- set file size due to need for large file support. Also note that
- this SetPathInfo is preferred to SetFileInfo based method in next
- routine which is only needed to work around a sharing violation bug
- in Samba which this routine can run into */
-
+/*
+ * We can not use write of zero bytes trick to set file size due to need for
+ * large file support. Also note that this SetPathInfo is preferred to
+ * SetFileInfo based method in next routine which is only needed to work around
+ * a sharing violation bugin Samba which this routine can run into.
+ */
int
CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
- const char *fileName, __u64 size, bool SetAllocation,
- const struct nls_table *nls_codepage, int remap)
+ const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
+ bool set_allocation)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -5409,6 +5409,8 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
int name_len;
int rc = 0;
int bytes_returned = 0;
+ int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
+
__u16 params, byte_count, data_count, param_offset, offset;
cFYI(1, "In SetEOF");
@@ -5420,14 +5422,14 @@ SetEOFRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
- PATH_MAX, nls_codepage, remap);
+ cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
+ PATH_MAX, cifs_sb->local_nls, remap);
name_len++; /* trailing null */
name_len *= 2;
} else { /* BB improve the check for buffer overruns BB */
- name_len = strnlen(fileName, PATH_MAX);
+ name_len = strnlen(file_name, PATH_MAX);
name_len++; /* trailing null */
- strncpy(pSMB->FileName, fileName, name_len);
+ strncpy(pSMB->FileName, file_name, name_len);
}
params = 6 + name_len;
data_count = sizeof(struct file_end_of_file_info);
@@ -5441,7 +5443,7 @@ SetEOFRetry:
param_offset = offsetof(struct smb_com_transaction2_spi_req,
InformationLevel) - 4;
offset = param_offset + params;
- if (SetAllocation) {
+ if (set_allocation) {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
@@ -5488,8 +5490,8 @@ SetEOFRetry:
}
int
-CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
- __u16 fid, __u32 pid_of_opener, bool SetAllocation)
+CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct file_end_of_file_info *parm_data;
@@ -5503,8 +5505,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
if (rc)
return rc;
- pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
- pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+ pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
+ pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
params = 6;
pSMB->MaxSetupCount = 0;
@@ -5533,8 +5535,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
+ offset);
pSMB->DataOffset = cpu_to_le16(offset);
parm_data->FileSize = cpu_to_le64(size);
- pSMB->Fid = fid;
- if (SetAllocation) {
+ pSMB->Fid = cfile->fid.netfid;
+ if (set_allocation) {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f1448d9..16101a0 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1883,7 +1883,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct tcon_link *tlink = NULL;
- struct cifs_tcon *pTcon = NULL;
+ struct cifs_tcon *tcon = NULL;
+ struct TCP_Server_Info *server;
struct cifs_io_parms io_parms;
/*
@@ -1897,19 +1898,21 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
*/
open_file = find_writable_file(cifsInode, true);
if (open_file) {
- __u16 nfid = open_file->fid.netfid;
- __u32 npid = open_file->pid;
- pTcon = tlink_tcon(open_file->tlink);
- rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
- npid, false);
+ tcon = tlink_tcon(open_file->tlink);
+ server = tcon->ses->server;
+ if (server->ops->set_file_size)
+ rc = server->ops->set_file_size(xid, tcon, open_file,
+ attrs->ia_size, false);
+ else
+ rc = -ENOSYS;
cifsFileInfo_put(open_file);
cFYI(1, "SetFSize for attrs rc = %d", rc);
if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
unsigned int bytes_written;
- io_parms.netfid = nfid;
- io_parms.pid = npid;
- io_parms.tcon = pTcon;
+ io_parms.netfid = open_file->fid.netfid;
+ io_parms.pid = open_file->pid;
+ io_parms.tcon = tcon;
io_parms.offset = 0;
io_parms.length = attrs->ia_size;
rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
@@ -1919,52 +1922,55 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
} else
rc = -EINVAL;
- if (rc != 0) {
- if (pTcon == NULL) {
- tlink = cifs_sb_tlink(cifs_sb);
- if (IS_ERR(tlink))
- return PTR_ERR(tlink);
- pTcon = tlink_tcon(tlink);
- }
+ if (!rc)
+ goto set_size_out;
- /* Set file size by pathname rather than by handle
- either because no valid, writeable file handle for
- it was found or because there was an error setting
- it by handle */
- rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
- false, cifs_sb->local_nls,
+ if (tcon == NULL) {
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+ server = tcon->ses->server;
+ }
+
+ /*
+ * Set file size by pathname rather than by handle either because no
+ * valid, writeable file handle for it was found or because there was
+ * an error setting it by handle.
+ */
+ if (server->ops->set_path_size)
+ rc = server->ops->set_path_size(xid, tcon, full_path,
+ attrs->ia_size, cifs_sb, false);
+ else
+ rc = -ENOSYS;
+ cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
+ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+ __u16 netfid;
+ int oplock = 0;
+
+ rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
+ GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
+ &oplock, NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
- if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
- __u16 netfid;
- int oplock = 0;
-
- rc = SMBLegacyOpen(xid, pTcon, full_path,
- FILE_OPEN, GENERIC_WRITE,
- CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- unsigned int bytes_written;
-
- io_parms.netfid = netfid;
- io_parms.pid = current->tgid;
- io_parms.tcon = pTcon;
- io_parms.offset = 0;
- io_parms.length = attrs->ia_size;
- rc = CIFSSMBWrite(xid, &io_parms,
- &bytes_written,
- NULL, NULL, 1);
- cFYI(1, "wrt seteof rc %d", rc);
- CIFSSMBClose(xid, pTcon, netfid);
- }
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == 0) {
+ unsigned int bytes_written;
+
+ io_parms.netfid = netfid;
+ io_parms.pid = current->tgid;
+ io_parms.tcon = tcon;
+ io_parms.offset = 0;
+ io_parms.length = attrs->ia_size;
+ rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
+ NULL, 1);
+ cFYI(1, "wrt seteof rc %d", rc);
+ CIFSSMBClose(xid, tcon, netfid);
}
- if (tlink)
- cifs_put_tlink(tlink);
}
+ if (tlink)
+ cifs_put_tlink(tlink);
+set_size_out:
if (rc == 0) {
cifsInode->server_eof = attrs->ia_size;
cifs_setsize(inode, attrs->ia_size);
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index e5d6344..b73d275 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -793,6 +793,8 @@ struct smb_version_operations smb1_operations = {
.query_path_info = cifs_query_path_info,
.query_file_info = cifs_query_file_info,
.get_srv_inum = cifs_get_srv_inum,
+ .set_path_size = CIFSSMBSetEOF,
+ .set_file_size = CIFSSMBSetFileSize,
.build_path_to_root = cifs_build_path_to_root,
.echo = CIFSSMBEcho,
.mkdir = CIFSSMBMkDir,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 36/45] CIFS: Add SMB2 support for set_file_size
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (34 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 35/45] CIFS: Move set_file_size to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 37/45] CIFS: Move set_file_info to ops struct Pavel Shilovsky
` (9 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2glob.h | 1 +
fs/cifs/smb2inode.c | 15 +++++++++++++++
fs/cifs/smb2ops.c | 11 +++++++++++
fs/cifs/smb2pdu.c | 26 +++++++++++++++++++++++---
fs/cifs/smb2pdu.h | 4 ++++
fs/cifs/smb2proto.h | 6 ++++++
6 files changed, 60 insertions(+), 3 deletions(-)
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 21555d8..05d429b 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -41,6 +41,7 @@
#define SMB2_OP_RENAME 6
#define SMB2_OP_DELETE 7
#define SMB2_OP_HARDLINK 8
+#define SMB2_OP_SET_EOF 9
/* Used when constructing chained read requests. */
#define CHAINED_REQUEST 1
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1921c9c..2905830 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -82,6 +82,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
volatile_fid, (__le16 *)data);
break;
+ case SMB2_OP_SET_EOF:
+ tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
+ current->tgid, (__le64 *)data);
+ break;
default:
cERROR(1, "Invalid command");
break;
@@ -217,3 +221,14 @@ smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
}
+
+int
+smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *full_path, __u64 size,
+ struct cifs_sb_info *cifs_sb, bool set_alloc)
+{
+ __le64 eof = cpu_to_le64(size);
+ return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
+ FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
+ SMB2_OP_SET_EOF);
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f9e3a13..3aad536 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -406,6 +406,15 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
return SMB2_write(xid, parms, written, iov, nr_segs);
}
+static int
+smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
+{
+ __le64 eof = cpu_to_le64(size);
+ return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
+ cfile->fid.volatile_fid, cfile->pid, &eof);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -437,6 +446,8 @@ struct smb_version_operations smb21_operations = {
.query_path_info = smb2_query_path_info,
.get_srv_inum = smb2_get_srv_inum,
.query_file_info = smb2_query_file_info,
+ .set_path_size = smb2_set_path_size,
+ .set_file_size = smb2_set_file_size,
.build_path_to_root = smb2_build_path_to_root,
.mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 4d9ef2c..f1edc5e 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1600,7 +1600,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
static int
send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid, int info_class,
+ u64 persistent_fid, u64 volatile_fid, u32 pid, int info_class,
unsigned int num, void **data, unsigned int *size)
{
struct smb2_set_info_req *req;
@@ -1630,6 +1630,8 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+ req->hdr.ProcessId = cpu_to_le32(pid);
+
req->InfoType = SMB2_O_INFO_FILE;
req->FileInfoClass = info_class;
req->PersistentFileId = persistent_fid;
@@ -1700,7 +1702,8 @@ SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
size[1] = len + 2 /* null */;
rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
- FILE_RENAME_INFORMATION, 2, data, size);
+ current->tgid, FILE_RENAME_INFORMATION, 2, data,
+ size);
kfree(data);
return rc;
}
@@ -1731,7 +1734,24 @@ SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
size[1] = len + 2 /* null */;
rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
- FILE_LINK_INFORMATION, 2, data, size);
+ current->tgid, FILE_LINK_INFORMATION, 2, data, size);
kfree(data);
return rc;
}
+
+int
+SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+ u64 volatile_fid, u32 pid, __le64 *eof)
+{
+ struct smb2_file_eof_info info;
+ void *data;
+ unsigned int size;
+
+ info.EndOfFile = *eof;
+
+ data = &info;
+ size = sizeof(struct smb2_file_eof_info);
+
+ return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
+ FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 34a9329..45ecae9 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -688,4 +688,8 @@ struct smb2_file_all_info { /* data block encoding of response to level 18 */
char FileName[1];
} __packed; /* level 18 Query */
+struct smb2_file_eof_info { /* encoding of request for level 10 */
+ __le64 EndOfFile; /* new end of file value */
+} __packed; /* level 20 Set */
+
#endif /* _SMB2PDU_H */
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 99f6945..3d48662 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -56,6 +56,9 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const char *full_path, FILE_ALL_INFO *data,
bool *adjust_tz);
+extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *full_path, __u64 size,
+ struct cifs_sb_info *cifs_sb, bool set_alloc);
extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -118,5 +121,8 @@ extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le16 *target_file);
+extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, u32 pid,
+ __le64 *eof);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 37/45] CIFS: Move set_file_info to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (35 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 36/45] CIFS: Add SMB2 support for set_file_size Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 38/45] CIFS: Add set_file_info support for SMB2 Pavel Shilovsky
` (8 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 3 ++
fs/cifs/inode.c | 79 ++++------------------------------------------------
fs/cifs/smb1ops.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+), 73 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 3f7a53d..7c20d5a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -258,6 +258,9 @@ struct smb_version_operations {
/* set size by file handle */
int (*set_file_size)(const unsigned int, struct cifs_tcon *,
struct cifsFileInfo *, __u64, bool);
+ /* set attributes */
+ int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
+ const unsigned int);
/* build a full path to the root of the mount */
char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *,
struct cifs_tcon *);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 16101a0..92c6c27 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -888,21 +888,18 @@ int
cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
char *full_path, __u32 dosattr)
{
- int rc;
- int oplock = 0;
- __u16 netfid;
- __u32 netpid;
bool set_time = false;
- struct cifsFileInfo *open_file;
- struct cifsInodeInfo *cifsInode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
- struct tcon_link *tlink = NULL;
- struct cifs_tcon *pTcon;
+ struct TCP_Server_Info *server;
FILE_BASIC_INFO info_buf;
if (attrs == NULL)
return -EINVAL;
+ server = cifs_sb_master_tcon(cifs_sb)->ses->server;
+ if (!server->ops->set_file_info)
+ return -ENOSYS;
+
if (attrs->ia_valid & ATTR_ATIME) {
set_time = true;
info_buf.LastAccessTime =
@@ -933,71 +930,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
info_buf.CreationTime = 0; /* don't change */
info_buf.Attributes = cpu_to_le32(dosattr);
- /*
- * If the file is already open for write, just use that fileid
- */
- open_file = find_writable_file(cifsInode, true);
- if (open_file) {
- netfid = open_file->fid.netfid;
- netpid = open_file->pid;
- pTcon = tlink_tcon(open_file->tlink);
- goto set_via_filehandle;
- }
-
- tlink = cifs_sb_tlink(cifs_sb);
- if (IS_ERR(tlink)) {
- rc = PTR_ERR(tlink);
- tlink = NULL;
- goto out;
- }
- pTcon = tlink_tcon(tlink);
-
- /*
- * NT4 apparently returns success on this call, but it doesn't
- * really work.
- */
- if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
- rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
- &info_buf, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc == 0) {
- cifsInode->cifsAttrs = dosattr;
- goto out;
- } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
- goto out;
- }
-
- cFYI(1, "calling SetFileInfo since SetPathInfo for "
- "times not supported by this server");
- rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
- SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
- CREATE_NOT_DIR, &netfid, &oplock,
- NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR);
-
- if (rc != 0) {
- if (rc == -EIO)
- rc = -EINVAL;
- goto out;
- }
-
- netpid = current->tgid;
-
-set_via_filehandle:
- rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
- if (!rc)
- cifsInode->cifsAttrs = dosattr;
-
- if (open_file == NULL)
- CIFSSMBClose(xid, pTcon, netfid);
- else
- cifsFileInfo_put(open_file);
-out:
- if (tlink != NULL)
- cifs_put_tlink(tlink);
- return rc;
+ return server->ops->set_file_info(inode, full_path, &info_buf, xid);
}
/*
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index b73d275..ed31196 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -758,6 +758,84 @@ cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
}
+static int
+smb_set_file_info(struct inode *inode, const char *full_path,
+ FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+ int oplock = 0;
+ int rc;
+ __u16 netfid;
+ __u32 netpid;
+ struct cifsFileInfo *open_file;
+ struct cifsInodeInfo *cinode = CIFS_I(inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct tcon_link *tlink = NULL;
+ struct cifs_tcon *tcon;
+ FILE_BASIC_INFO info_buf;
+
+ /* if the file is already open for write, just use that fileid */
+ open_file = find_writable_file(cinode, true);
+ if (open_file) {
+ netfid = open_file->fid.netfid;
+ netpid = open_file->pid;
+ tcon = tlink_tcon(open_file->tlink);
+ goto set_via_filehandle;
+ }
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink)) {
+ rc = PTR_ERR(tlink);
+ tlink = NULL;
+ goto out;
+ }
+ tcon = tlink_tcon(tlink);
+
+ /*
+ * NT4 apparently returns success on this call, but it doesn't really
+ * work.
+ */
+ if (!(tcon->ses->flags & CIFS_SES_NT4)) {
+ rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc == 0) {
+ cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+ goto out;
+ } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
+ goto out;
+ }
+
+ cFYI(1, "calling SetFileInfo since SetPathInfo for times not supported "
+ "by this server");
+ rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+ SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
+ &netfid, &oplock, NULL, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+ if (rc != 0) {
+ if (rc == -EIO)
+ rc = -EINVAL;
+ goto out;
+ }
+
+ netpid = current->tgid;
+
+set_via_filehandle:
+ rc = CIFSSMBSetFileInfo(xid, tcon, &info_buf, netfid, netpid);
+ if (!rc)
+ cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+
+ if (open_file == NULL)
+ CIFSSMBClose(xid, tcon, netfid);
+ else
+ cifsFileInfo_put(open_file);
+out:
+ if (tlink != NULL)
+ cifs_put_tlink(tlink);
+ return rc;
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -795,6 +873,7 @@ struct smb_version_operations smb1_operations = {
.get_srv_inum = cifs_get_srv_inum,
.set_path_size = CIFSSMBSetEOF,
.set_file_size = CIFSSMBSetFileSize,
+ .set_file_info = smb_set_file_info,
.build_path_to_root = cifs_build_path_to_root,
.echo = CIFSSMBEcho,
.mkdir = CIFSSMBMkDir,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 38/45] CIFS: Add set_file_info support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (36 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 37/45] CIFS: Move set_file_info to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 39/45] CIFS: Move readdir code to ops struct Pavel Shilovsky
` (7 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2inode.c | 22 ++++++++++++++++++++++
fs/cifs/smb2ops.c | 1 +
fs/cifs/smb2pdu.c | 11 +++++++++++
fs/cifs/smb2proto.h | 5 +++++
4 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 2905830..1bd6b0f 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -86,6 +86,10 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
current->tgid, (__le64 *)data);
break;
+ case SMB2_OP_SET_INFO:
+ tmprc = SMB2_set_info(xid, tcon, persistent_fid, volatile_fid,
+ (FILE_BASIC_INFO *)data);
+ break;
default:
cERROR(1, "Invalid command");
break;
@@ -232,3 +236,21 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
SMB2_OP_SET_EOF);
}
+
+int
+smb2_set_file_info(struct inode *inode, const char *full_path,
+ FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+ struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+ struct tcon_link *tlink;
+ int rc;
+
+ tlink = cifs_sb_tlink(cifs_sb);
+ if (IS_ERR(tlink))
+ return PTR_ERR(tlink);
+ rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
+ FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, 0, buf,
+ SMB2_OP_SET_INFO);
+ cifs_put_tlink(tlink);
+ return rc;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 3aad536..7ecb117 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -448,6 +448,7 @@ struct smb_version_operations smb21_operations = {
.query_file_info = smb2_query_file_info,
.set_path_size = smb2_set_path_size,
.set_file_size = smb2_set_file_size,
+ .set_file_info = smb2_set_file_info,
.build_path_to_root = smb2_build_path_to_root,
.mkdir = smb2_mkdir,
.mkdir_setinfo = smb2_mkdir_setinfo,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index f1edc5e..1587761 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1755,3 +1755,14 @@ SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
}
+
+int
+SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, FILE_BASIC_INFO *buf)
+{
+ unsigned int size;
+ size = sizeof(FILE_BASIC_INFO);
+ return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+ current->tgid, FILE_BASIC_INFORMATION, 1,
+ (void **)&buf, &size);
+}
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 3d48662..2774724 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -59,6 +59,8 @@ extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
const char *full_path, __u64 size,
struct cifs_sb_info *cifs_sb, bool set_alloc);
+extern int smb2_set_file_info(struct inode *inode, const char *full_path,
+ FILE_BASIC_INFO *buf, const unsigned int xid);
extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
const char *name, struct cifs_sb_info *cifs_sb);
extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -124,5 +126,8 @@ extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u32 pid,
__le64 *eof);
+extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid,
+ FILE_BASIC_INFO *buf);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 39/45] CIFS: Move readdir code to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (37 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 38/45] CIFS: Add set_file_info support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 40/45] CIFS: Add readdir support for SMB2 Pavel Shilovsky
` (6 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 15 +++++
fs/cifs/cifsproto.h | 2 +-
fs/cifs/file.c | 62 +++++++++++--------
fs/cifs/netmisc.c | 3 +-
fs/cifs/readdir.c | 165 ++++++++++++++++++++++++++++-----------------------
fs/cifs/smb1ops.c | 31 ++++++++++
6 files changed, 174 insertions(+), 104 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7c20d5a..406ad6d 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -177,6 +177,7 @@ struct cifs_fid;
struct cifs_readdata;
struct cifs_writedata;
struct cifs_io_parms;
+struct cifs_search_info;
struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -313,6 +314,20 @@ struct smb_version_operations {
int (*sync_write)(const unsigned int, struct cifsFileInfo *,
struct cifs_io_parms *, unsigned int *, struct kvec *,
unsigned long);
+ /* open dir, start readdir */
+ int (*query_dir_first)(const unsigned int, struct cifs_tcon *,
+ const char *, struct cifs_sb_info *,
+ struct cifs_fid *, __u16,
+ struct cifs_search_info *);
+ /* continue readdir */
+ int (*query_dir_next)(const unsigned int, struct cifs_tcon *,
+ struct cifs_fid *,
+ __u16, struct cifs_search_info *srch_inf);
+ /* close dir */
+ int (*close_dir)(const unsigned int, struct cifs_tcon *,
+ struct cifs_fid *);
+ /* calculate a size of SMB message */
+ unsigned int (*calc_smb_size)(void *);
};
struct smb_version_values {
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6e04941..afc0797 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -100,7 +100,7 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
unsigned int bytes_written);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern unsigned int smbCalcSize(void *buf);
extern int decode_negTokenInit(unsigned char *security_blob, int length,
struct TCP_Server_Info *server);
extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2ffee05..da9dc50 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -609,39 +609,47 @@ int cifs_closedir(struct inode *inode, struct file *file)
int rc = 0;
unsigned int xid;
struct cifsFileInfo *cfile = file->private_data;
- char *tmp;
+ struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
+ char *buf;
cFYI(1, "Closedir inode = 0x%p", inode);
+ if (cfile == NULL)
+ return rc;
+
xid = get_xid();
+ tcon = tlink_tcon(cfile->tlink);
+ server = tcon->ses->server;
- if (cfile) {
- struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+ cFYI(1, "Freeing private data in close dir");
+ spin_lock(&cifs_file_list_lock);
+ if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+ cfile->invalidHandle = true;
+ spin_unlock(&cifs_file_list_lock);
+ if (server->ops->close_dir)
+ rc = server->ops->close_dir(xid, tcon, &cfile->fid);
+ else
+ rc = -ENOSYS;
+ cFYI(1, "Closing uncompleted readdir with rc %d", rc);
+ /* not much we can do if it fails anyway, ignore rc */
+ rc = 0;
+ } else
+ spin_unlock(&cifs_file_list_lock);
- cFYI(1, "Freeing private data in close dir");
- spin_lock(&cifs_file_list_lock);
- if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
- cfile->invalidHandle = true;
- spin_unlock(&cifs_file_list_lock);
- rc = CIFSFindClose(xid, tcon, cfile->fid.netfid);
- cFYI(1, "Closing uncompleted readdir with rc %d", rc);
- /* not much we can do if it fails anyway, ignore rc */
- rc = 0;
- } else
- spin_unlock(&cifs_file_list_lock);
- tmp = cfile->srch_inf.ntwrk_buf_start;
- if (tmp) {
- cFYI(1, "closedir free smb buf in srch struct");
- cfile->srch_inf.ntwrk_buf_start = NULL;
- if (cfile->srch_inf.smallBuf)
- cifs_small_buf_release(tmp);
- else
- cifs_buf_release(tmp);
- }
- cifs_put_tlink(cfile->tlink);
- kfree(file->private_data);
- file->private_data = NULL;
+ buf = cfile->srch_inf.ntwrk_buf_start;
+ if (buf) {
+ cFYI(1, "closedir free smb buf in srch struct");
+ cfile->srch_inf.ntwrk_buf_start = NULL;
+ if (cfile->srch_inf.smallBuf)
+ cifs_small_buf_release(buf);
+ else
+ cifs_buf_release(buf);
}
+
+ cifs_put_tlink(cfile->tlink);
+ kfree(file->private_data);
+ file->private_data = NULL;
/* BB can we lock the filestruct while this is going on? */
free_xid(xid);
return rc;
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 581c225..e7bab3b 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -913,8 +913,9 @@ map_smb_to_linux_error(char *buf, bool logErr)
* portion, the number of word parameters and the data portion of the message
*/
unsigned int
-smbCalcSize(struct smb_hdr *ptr)
+smbCalcSize(void *buf)
{
+ struct smb_hdr *ptr = (struct smb_hdr *)buf;
return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
2 /* size of the bcc field */ + get_bcc(ptr));
}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 9e76e3b..b0f4a42 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -220,7 +220,8 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
}
*/
-static int initiate_cifs_search(const unsigned int xid, struct file *file)
+static int
+initiate_cifs_search(const unsigned int xid, struct file *file)
{
__u16 search_flags;
int rc = 0;
@@ -229,6 +230,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon;
+ struct TCP_Server_Info *server;
if (file->private_data == NULL) {
tlink = cifs_sb_tlink(cifs_sb);
@@ -248,6 +250,13 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
tcon = tlink_tcon(cifsFile->tlink);
}
+ server = tcon->ses->server;
+
+ if (!server->ops->query_dir_first) {
+ rc = -ENOSYS;
+ goto error_exit;
+ }
+
cifsFile->invalidHandle = true;
cifsFile->srch_inf.endOfSearch = false;
@@ -278,10 +287,10 @@ ffirst_retry:
if (backup_cred(cifs_sb))
search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
- rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
- &cifsFile->fid.netfid, search_flags, &cifsFile->srch_inf,
- cifs_sb->mnt_cifs_flags &
- CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+ rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb,
+ &cifsFile->fid, search_flags,
+ &cifsFile->srch_inf);
+
if (rc == 0)
cifsFile->invalidHandle = false;
/* BB add following call to handle readdir on new NTFS symlink errors
@@ -501,62 +510,67 @@ static int cifs_save_resume_key(const char *current_entry,
return rc;
}
-/* find the corresponding entry in the search */
-/* Note that the SMB server returns search entries for . and .. which
- complicates logic here if we choose to parse for them and we do not
- assume that they are located in the findfirst return buffer.*/
-/* We start counting in the buffer with entry 2 and increment for every
- entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
- struct file *file, char **ppCurrentEntry, int *num_to_ret)
+/*
+ * Find the corresponding entry in the search. Note that the SMB server returns
+ * search entries for . and .. which complicates logic here if we choose to
+ * parse for them and we do not assume that they are located in the findfirst
+ * return buffer. We start counting in the buffer with entry 2 and increment for
+ * every entry (do not increment for . or .. entry).
+ */
+static int
+find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
+ struct file *file, char **current_entry, int *num_to_ret)
{
__u16 search_flags;
int rc = 0;
int pos_in_buf = 0;
loff_t first_entry_in_buffer;
loff_t index_to_find = file->f_pos;
- struct cifsFileInfo *cifsFile = file->private_data;
+ struct cifsFileInfo *cfile = file->private_data;
struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ struct TCP_Server_Info *server = tcon->ses->server;
/* check if index in the buffer */
- if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
- (num_to_ret == NULL))
+ if (!server->ops->query_dir_first || !server->ops->query_dir_next)
+ return -ENOSYS;
+
+ if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
return -ENOENT;
- *ppCurrentEntry = NULL;
- first_entry_in_buffer =
- cifsFile->srch_inf.index_of_last_entry -
- cifsFile->srch_inf.entries_in_buffer;
+ *current_entry = NULL;
+ first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
+ cfile->srch_inf.entries_in_buffer;
- /* if first entry in buf is zero then is first buffer
- in search response data which means it is likely . and ..
- will be in this buffer, although some servers do not return
- . and .. for the root of a drive and for those we need
- to start two entries earlier */
+ /*
+ * If first entry in buf is zero then is first buffer
+ * in search response data which means it is likely . and ..
+ * will be in this buffer, although some servers do not return
+ * . and .. for the root of a drive and for those we need
+ * to start two entries earlier.
+ */
dump_cifs_file_struct(file, "In fce ");
- if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
- is_dir_changed(file)) ||
- (index_to_find < first_entry_in_buffer)) {
+ if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
+ is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
/* close and restart search */
cFYI(1, "search backing up - close and restart search");
spin_lock(&cifs_file_list_lock);
- if (!cifsFile->srch_inf.endOfSearch &&
- !cifsFile->invalidHandle) {
- cifsFile->invalidHandle = true;
+ if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+ cfile->invalidHandle = true;
spin_unlock(&cifs_file_list_lock);
- CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
+ if (server->ops->close)
+ server->ops->close(xid, tcon, &cfile->fid);
} else
spin_unlock(&cifs_file_list_lock);
- if (cifsFile->srch_inf.ntwrk_buf_start) {
+ if (cfile->srch_inf.ntwrk_buf_start) {
cFYI(1, "freeing SMB ff cache buf on search rewind");
- if (cifsFile->srch_inf.smallBuf)
- cifs_small_buf_release(cifsFile->srch_inf.
+ if (cfile->srch_inf.smallBuf)
+ cifs_small_buf_release(cfile->srch_inf.
ntwrk_buf_start);
else
- cifs_buf_release(cifsFile->srch_inf.
+ cifs_buf_release(cfile->srch_inf.
ntwrk_buf_start);
- cifsFile->srch_inf.ntwrk_buf_start = NULL;
+ cfile->srch_inf.ntwrk_buf_start = NULL;
}
rc = initiate_cifs_search(xid, file);
if (rc) {
@@ -565,65 +579,64 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
return rc;
}
/* FindFirst/Next set last_entry to NULL on malformed reply */
- if (cifsFile->srch_inf.last_entry)
- cifs_save_resume_key(cifsFile->srch_inf.last_entry,
- cifsFile);
+ if (cfile->srch_inf.last_entry)
+ cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
}
search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
if (backup_cred(cifs_sb))
search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
- while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
- (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
+ while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
+ (rc == 0) && !cfile->srch_inf.endOfSearch) {
cFYI(1, "calling findnext2");
- rc = CIFSFindNext(xid, pTcon, cifsFile->fid.netfid,
- search_flags, &cifsFile->srch_inf);
+ rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
+ search_flags,
+ &cfile->srch_inf);
/* FindFirst/Next set last_entry to NULL on malformed reply */
- if (cifsFile->srch_inf.last_entry)
- cifs_save_resume_key(cifsFile->srch_inf.last_entry,
- cifsFile);
+ if (cfile->srch_inf.last_entry)
+ cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
if (rc)
return -ENOENT;
}
- if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+ if (index_to_find < cfile->srch_inf.index_of_last_entry) {
/* we found the buffer that contains the entry */
/* scan and find it */
int i;
- char *current_entry;
- char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
- smbCalcSize((struct smb_hdr *)
- cifsFile->srch_inf.ntwrk_buf_start);
-
- current_entry = cifsFile->srch_inf.srch_entries_start;
- first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- - cifsFile->srch_inf.entries_in_buffer;
+ char *cur_ent;
+ char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
+ server->ops->calc_smb_size(
+ cfile->srch_inf.ntwrk_buf_start);
+
+ cur_ent = cfile->srch_inf.srch_entries_start;
+ first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
+ - cfile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_in_buffer;
cFYI(1, "found entry - pos_in_buf %d", pos_in_buf);
- for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
+ for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
/* go entry by entry figuring out which is first */
- current_entry = nxt_dir_entry(current_entry, end_of_smb,
- cifsFile->srch_inf.info_level);
+ cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
+ cfile->srch_inf.info_level);
}
- if ((current_entry == NULL) && (i < pos_in_buf)) {
+ if ((cur_ent == NULL) && (i < pos_in_buf)) {
/* BB fixme - check if we should flag this error */
cERROR(1, "reached end of buf searching for pos in buf"
- " %d index to find %lld rc %d",
- pos_in_buf, index_to_find, rc);
+ " %d index to find %lld rc %d", pos_in_buf,
+ index_to_find, rc);
}
rc = 0;
- *ppCurrentEntry = current_entry;
+ *current_entry = cur_ent;
} else {
cFYI(1, "index not in buffer - could not findnext into it");
return 0;
}
- if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+ if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
cFYI(1, "can not return entries pos_in_buf beyond last");
*num_to_ret = 0;
} else
- *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
+ *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
return rc;
}
@@ -723,7 +736,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
int rc = 0;
unsigned int xid;
int i;
- struct cifs_tcon *pTcon;
+ struct cifs_tcon *tcon;
struct cifsFileInfo *cifsFile = NULL;
char *current_entry;
int num_to_fill = 0;
@@ -781,12 +794,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
}
} /* else {
cifsFile->invalidHandle = true;
- CIFSFindClose(xid, pTcon, cifsFile->fid.netfid);
+ tcon->ses->server->close(xid, tcon, &cifsFile->fid);
} */
- pTcon = tlink_tcon(cifsFile->tlink);
- rc = find_cifs_entry(xid, pTcon, file,
- ¤t_entry, &num_to_fill);
+ tcon = tlink_tcon(cifsFile->tlink);
+ rc = find_cifs_entry(xid, tcon, file, ¤t_entry,
+ &num_to_fill);
if (rc) {
cFYI(1, "fce error %d", rc);
goto rddir2_exit;
@@ -798,7 +811,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
}
cFYI(1, "loop through %d times filling dir for net buf %p",
num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
- max_len = smbCalcSize((struct smb_hdr *)
+ max_len = tcon->ses->server->ops->calc_smb_size(
cifsFile->srch_inf.ntwrk_buf_start);
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
@@ -815,10 +828,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
num_to_fill, i);
break;
}
- /* if buggy server returns . and .. late do
- we want to check for that here? */
- rc = cifs_filldir(current_entry, file,
- filldir, direntry, tmp_buf, max_len);
+ /*
+ * if buggy server returns . and .. late do we want to
+ * check for that here?
+ */
+ rc = cifs_filldir(current_entry, file, filldir,
+ direntry, tmp_buf, max_len);
if (rc == -EOVERFLOW) {
rc = 0;
break;
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index ed31196..068d609 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -836,6 +836,33 @@ out:
return rc;
}
+static int
+cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *path, struct cifs_sb_info *cifs_sb,
+ struct cifs_fid *fid, __u16 search_flags,
+ struct cifs_search_info *srch_inf)
+{
+ return CIFSFindFirst(xid, tcon, path, cifs_sb->local_nls,
+ &fid->netfid, search_flags, srch_inf,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+}
+
+static int
+cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid, __u16 search_flags,
+ struct cifs_search_info *srch_inf)
+{
+ return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf);
+}
+
+static int
+cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid)
+{
+ return CIFSFindClose(xid, tcon, fid->netfid);
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -891,6 +918,10 @@ struct smb_version_operations smb1_operations = {
.async_writev = cifs_async_writev,
.sync_read = cifs_sync_read,
.sync_write = cifs_sync_write,
+ .query_dir_first = cifs_query_dir_first,
+ .query_dir_next = cifs_query_dir_next,
+ .close_dir = cifs_close_dir,
+ .calc_smb_size = smbCalcSize,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 40/45] CIFS: Add readdir support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (38 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 39/45] CIFS: Move readdir code to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 41/45] CIFS: Process oplocks " Pavel Shilovsky
` (5 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2misc.c | 8 ++-
fs/cifs/smb2ops.c | 57 +++++++++++++++++
fs/cifs/smb2pdu.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 28 +++++++++
fs/cifs/smb2proto.h | 5 +-
5 files changed, 264 insertions(+), 2 deletions(-)
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index cbb69e2..81fb162 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -246,6 +246,11 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
*len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
break;
case SMB2_QUERY_DIRECTORY:
+ *off = le16_to_cpu(
+ ((struct smb2_query_directory_rsp *)hdr)->OutputBufferOffset);
+ *len = le32_to_cpu(
+ ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
+ break;
case SMB2_IOCTL:
case SMB2_CHANGE_NOTIFY:
default:
@@ -288,8 +293,9 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
* portion, the number of word parameters and the data portion of the message.
*/
unsigned int
-smb2_calc_size(struct smb2_hdr *hdr)
+smb2_calc_size(void *buf)
{
+ struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
int offset; /* the offset from the beginning of SMB to data area */
int data_length; /* the length of the variable length data area */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 7ecb117..0ea6cfe 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -415,6 +415,59 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
cfile->fid.volatile_fid, cfile->pid, &eof);
}
+static int
+smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+ const char *path, struct cifs_sb_info *cifs_sb,
+ struct cifs_fid *fid, __u16 search_flags,
+ struct cifs_search_info *srch_inf)
+{
+ __le16 *utf16_path;
+ int rc;
+ __u64 persistent_fid, volatile_fid;
+
+ utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (!utf16_path)
+ return -ENOMEM;
+
+ rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
+ FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
+ NULL);
+ kfree(utf16_path);
+ if (rc) {
+ cERROR(1, "open dir failed");
+ return rc;
+ }
+
+ srch_inf->entries_in_buffer = 0;
+ srch_inf->index_of_last_entry = 0;
+ fid->persistent_fid = persistent_fid;
+ fid->volatile_fid = volatile_fid;
+
+ rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid, 0,
+ srch_inf);
+ if (rc) {
+ cERROR(1, "query directory failed");
+ SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+ }
+ return rc;
+}
+
+static int
+smb2_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid, __u16 search_flags,
+ struct cifs_search_info *srch_inf)
+{
+ return SMB2_query_directory(xid, tcon, fid->persistent_fid,
+ fid->volatile_fid, 0, srch_inf);
+}
+
+static int
+smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+ struct cifs_fid *fid)
+{
+ return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -464,6 +517,10 @@ struct smb_version_operations smb21_operations = {
.async_writev = smb2_async_writev,
.sync_read = smb2_sync_read,
.sync_write = smb2_sync_write,
+ .query_dir_first = smb2_query_dir_first,
+ .query_dir_next = smb2_query_dir_next,
+ .close_dir = smb2_close_dir,
+ .calc_smb_size = smb2_calc_size,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 1587761..181b4db 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -45,6 +45,7 @@
#include "ntlmssp.h"
#include "smb2status.h"
#include "smb2glob.h"
+#include "cifspdu.h"
/*
* The following table defines the expected "StructureSize" of SMB2 requests
@@ -1598,6 +1599,173 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
return rc;
}
+static unsigned int
+num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
+{
+ int len;
+ unsigned int entrycount = 0;
+ unsigned int next_offset = 0;
+ FILE_DIRECTORY_INFO *entryptr;
+
+ if (bufstart == NULL)
+ return 0;
+
+ entryptr = (FILE_DIRECTORY_INFO *)bufstart;
+
+ while (1) {
+ entryptr = (FILE_DIRECTORY_INFO *)
+ ((char *)entryptr + next_offset);
+
+ if ((char *)entryptr + size > end_of_buf) {
+ cERROR(1, "malformed search entry would overflow");
+ break;
+ }
+
+ len = le32_to_cpu(entryptr->FileNameLength);
+ if ((char *)entryptr + len + size > end_of_buf) {
+ cERROR(1, "directory entry name would overflow frame "
+ "end of buf %p", end_of_buf);
+ break;
+ }
+
+ *lastentry = (char *)entryptr;
+ entrycount++;
+
+ next_offset = le32_to_cpu(entryptr->NextEntryOffset);
+ if (!next_offset)
+ break;
+ }
+
+ return entrycount;
+}
+
+/*
+ * Readdir/FindFirst
+ */
+int
+SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, int index,
+ struct cifs_search_info *srch_inf)
+{
+ struct smb2_query_directory_req *req;
+ struct smb2_query_directory_rsp *rsp = NULL;
+ struct kvec iov[2];
+ int rc = 0;
+ int len;
+ int resp_buftype;
+ unsigned char *bufptr;
+ struct TCP_Server_Info *server;
+ struct cifs_ses *ses = tcon->ses;
+ __le16 asteriks = cpu_to_le16('*');
+ char *end_of_smb;
+ unsigned int output_size = CIFSMaxBufSize;
+ size_t info_buf_size;
+
+ if (ses && (ses->server))
+ server = ses->server;
+ else
+ return -EIO;
+
+ rc = small_smb2_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req);
+ if (rc)
+ return rc;
+
+ switch (srch_inf->info_level) {
+ case SMB_FIND_FILE_DIRECTORY_INFO:
+ req->FileInformationClass = FILE_DIRECTORY_INFORMATION;
+ info_buf_size = sizeof(FILE_DIRECTORY_INFO) - 1;
+ break;
+ case SMB_FIND_FILE_ID_FULL_DIR_INFO:
+ req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
+ info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
+ break;
+ default:
+ cERROR(1, "info level %u isn't supported",
+ srch_inf->info_level);
+ rc = -EINVAL;
+ goto qdir_exit;
+ }
+
+ req->FileIndex = cpu_to_le32(index);
+ req->PersistentFileId = persistent_fid;
+ req->VolatileFileId = volatile_fid;
+
+ len = 0x2;
+ bufptr = req->Buffer;
+ memcpy(bufptr, &asteriks, len);
+
+ req->FileNameOffset =
+ cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1 - 4);
+ req->FileNameLength = cpu_to_le16(len);
+ /*
+ * BB could be 30 bytes or so longer if we used SMB2 specific
+ * buffer lengths, but this is safe and close enough.
+ */
+ output_size = min_t(unsigned int, output_size, server->maxBuf);
+ output_size = min_t(unsigned int, output_size, 2 << 15);
+ req->OutputBufferLength = cpu_to_le32(output_size);
+
+ iov[0].iov_base = (char *)req;
+ /* 4 for RFC1001 length and 1 for Buffer */
+ iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+ iov[1].iov_base = (char *)(req->Buffer);
+ iov[1].iov_len = len;
+
+ inc_rfc1001_len(req, len - 1 /* Buffer */);
+
+ rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
+ goto qdir_exit;
+ }
+ rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
+
+ rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+ le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+ info_buf_size);
+ if (rc)
+ goto qdir_exit;
+
+ srch_inf->unicode = true;
+
+ if (srch_inf->ntwrk_buf_start) {
+ if (srch_inf->smallBuf)
+ cifs_small_buf_release(srch_inf->ntwrk_buf_start);
+ else
+ cifs_buf_release(srch_inf->ntwrk_buf_start);
+ }
+ srch_inf->ntwrk_buf_start = (char *)rsp;
+ srch_inf->srch_entries_start = srch_inf->last_entry = 4 /* rfclen */ +
+ (char *)&rsp->hdr + le16_to_cpu(rsp->OutputBufferOffset);
+ /* 4 for rfc1002 length field */
+ end_of_smb = get_rfc1002_length(rsp) + 4 + (char *)&rsp->hdr;
+ srch_inf->entries_in_buffer =
+ num_entries(srch_inf->srch_entries_start, end_of_smb,
+ &srch_inf->last_entry, info_buf_size);
+ srch_inf->index_of_last_entry += srch_inf->entries_in_buffer;
+ cFYI(1, "num entries %d last_index %lld srch start %p srch end %p",
+ srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
+ srch_inf->srch_entries_start, srch_inf->last_entry);
+ if (resp_buftype == CIFS_LARGE_BUFFER)
+ srch_inf->smallBuf = false;
+ else if (resp_buftype == CIFS_SMALL_BUFFER)
+ srch_inf->smallBuf = true;
+ else
+ cERROR(1, "illegal search buffer type");
+
+ if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
+ srch_inf->endOfSearch = 1;
+ else
+ srch_inf->endOfSearch = 0;
+
+ return rc;
+
+qdir_exit:
+ free_rsp_buf(resp_buftype, rsp);
+ return rc;
+}
+
static int
send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid, u32 pid, int info_class,
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 45ecae9..cd64385 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -536,6 +536,34 @@ struct smb2_echo_rsp {
__u16 Reserved;
} __packed;
+/* search (query_directory) Flags field */
+#define SMB2_RESTART_SCANS 0x01
+#define SMB2_RETURN_SINGLE_ENTRY 0x02
+#define SMB2_INDEX_SPECIFIED 0x04
+#define SMB2_REOPEN 0x10
+
+struct smb2_query_directory_req {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 33 */
+ __u8 FileInformationClass;
+ __u8 Flags;
+ __le32 FileIndex;
+ __u64 PersistentFileId; /* opaque endianness */
+ __u64 VolatileFileId; /* opaque endianness */
+ __le16 FileNameOffset;
+ __le16 FileNameLength;
+ __le32 OutputBufferLength;
+ __u8 Buffer[1];
+} __packed;
+
+struct smb2_query_directory_rsp {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 9 */
+ __le16 OutputBufferOffset;
+ __le32 OutputBufferLength;
+ __u8 Buffer[1];
+} __packed;
+
/* Possible InfoType values */
#define SMB2_O_INFO_FILE 0x01
#define SMB2_O_INFO_FILESYSTEM 0x02
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 2774724..0d29db2 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -34,7 +34,7 @@ struct statfs;
*/
extern int map_smb2_to_linux_error(char *buf, bool log_err);
extern int smb2_check_message(char *buf, unsigned int length);
-extern unsigned int smb2_calc_size(struct smb2_hdr *hdr);
+extern unsigned int smb2_calc_size(void *buf);
extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
extern __le16 *cifs_convert_path_to_utf16(const char *from,
struct cifs_sb_info *cifs_sb);
@@ -117,6 +117,9 @@ extern int smb2_async_writev(struct cifs_writedata *wdata);
extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
unsigned int *nbytes, struct kvec *iov, int n_vec);
extern int SMB2_echo(struct TCP_Server_Info *server);
+extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, int index,
+ struct cifs_search_info *srch_inf);
extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
__le16 *target_file);
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 41/45] CIFS: Process oplocks for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (39 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 40/45] CIFS: Add readdir support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 42/45] CIFS: Move oplock break to ops struct Pavel Shilovsky
` (4 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <piastryyy-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
fs/cifs/cifsglob.h | 1 +
fs/cifs/connect.c | 4 ++++
fs/cifs/smb2file.c | 24 ++++++++++++++++++++++--
fs/cifs/smb2inode.c | 3 ++-
fs/cifs/smb2ops.c | 29 +++++++++++++++++++++++++----
fs/cifs/smb2pdu.c | 8 +++++---
fs/cifs/smb2proto.h | 3 ++-
7 files changed, 61 insertions(+), 11 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 406ad6d..133cd0c 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -328,6 +328,7 @@ struct smb_version_operations {
struct cifs_fid *);
/* calculate a size of SMB message */
unsigned int (*calc_smb_size)(void *);
+ bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
};
struct smb_version_values {
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index bd4dcdd..34f46d0 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -818,6 +818,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
cifs_dump_mem("Bad SMB: ", buf,
min_t(unsigned int, server->total_read, 48));
+ if (server->ops->is_status_pending &&
+ server->ops->is_status_pending(buf, server, length))
+ return -1;
+
if (!mid)
return length;
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index a7618df..5ff25e0 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -34,6 +34,26 @@
#include "fscache.h"
#include "smb2proto.h"
+void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+ oplock &= 0xFF;
+ if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ cinode->clientCanCacheAll = true;
+ cinode->clientCanCacheRead = true;
+ cFYI(1, "Exclusive Oplock granted on inode %p",
+ &cinode->vfs_inode);
+ } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+ cinode->clientCanCacheAll = false;
+ cinode->clientCanCacheRead = true;
+ cFYI(1, "Level II Oplock granted on inode %p",
+ &cinode->vfs_inode);
+ } else {
+ cinode->clientCanCacheAll = false;
+ cinode->clientCanCacheRead = false;
+ }
+}
+
int
smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
int disposition, int desired_access, int create_options,
@@ -58,10 +78,11 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
}
desired_access |= FILE_READ_ATTRIBUTES;
+ *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
&fid->volatile_fid, desired_access, disposition,
- 0, 0, smb2_data);
+ 0, 0, (__u8 *)oplock, smb2_data);
if (rc)
goto out;
@@ -79,7 +100,6 @@ smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
}
out:
- *oplock = 0;
kfree(smb2_data);
kfree(smb2_path);
return rc;
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 1bd6b0f..7064824 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -47,6 +47,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
int rc, tmprc = 0;
u64 persistent_fid, volatile_fid;
__le16 *utf16_path;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
if (!utf16_path)
@@ -54,7 +55,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
desired_access, create_disposition, file_attributes,
- create_options, NULL);
+ create_options, &oplock, NULL);
if (rc) {
kfree(utf16_path);
return rc;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0ea6cfe..25f4263 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -22,6 +22,7 @@
#include "smb2proto.h"
#include "cifsproto.h"
#include "cifs_debug.h"
+#include "smb2status.h"
static int
change_conf(struct TCP_Server_Info *server)
@@ -198,13 +199,14 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
int rc;
__u64 persistent_fid, volatile_fid;
__le16 *utf16_path;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
if (!utf16_path)
return -ENOMEM;
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
- FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, NULL);
+ FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
if (rc) {
kfree(utf16_path);
return rc;
@@ -349,10 +351,10 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
static void
smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
{
- /* struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode); */
+ struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
cfile->fid.persistent_fid = fid->persistent_fid;
cfile->fid.volatile_fid = fid->volatile_fid;
- /* cifs_set_oplock_level(cinode, oplock); */
+ smb2_set_oplock_level(cinode, oplock);
/* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
}
@@ -423,6 +425,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
{
__le16 *utf16_path;
int rc;
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
__u64 persistent_fid, volatile_fid;
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
@@ -431,7 +434,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
- NULL);
+ &oplock, NULL);
kfree(utf16_path);
if (rc) {
cERROR(1, "open dir failed");
@@ -468,6 +471,23 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
}
+/*
+* If we negotiate SMB2 protocol and get STATUS_PENDING - update
+* the number of credits and return true. Otherwise - return false.
+*/
+static bool
+smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
+{
+ struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+
+ if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
+ return false;
+
+ if (!length)
+ add_credits(server, le16_to_cpu(hdr->CreditRequest), 0);
+ return true;
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -521,6 +541,7 @@ struct smb_version_operations smb21_operations = {
.query_dir_next = smb2_query_dir_next,
.close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size,
+ .is_status_pending = smb2_is_status_pending,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 181b4db..58c1e91 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -872,7 +872,7 @@ int
SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
__u32 create_disposition, __u32 file_attributes, __u32 create_options,
- struct smb2_file_all_info *buf)
+ __u8 *oplock, struct smb2_file_all_info *buf)
{
struct smb2_create_req *req;
struct smb2_create_rsp *rsp;
@@ -895,9 +895,9 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
if (rc)
return rc;
- /* if (server->oplocks)
+ if (server->oplocks)
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
- else */
+ else
req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
req->ImpersonationLevel = IL_IMPERSONATION;
req->DesiredAccess = cpu_to_le32(desired_access);
@@ -954,6 +954,8 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
buf->NumberOfLinks = cpu_to_le32(1);
buf->DeletePending = 0;
}
+
+ *oplock = rsp->OplockLevel;
creat_exit:
free_rsp_buf(resp_buftype, rsp);
return rc;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 0d29db2..d18339f 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -82,6 +82,7 @@ extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
int desired_access, int create_options,
struct cifs_fid *fid, __u32 *oplock,
FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
/*
* SMB2 Worker functions - most of protocol specific implementation details
@@ -99,7 +100,7 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
__le16 *path, u64 *persistent_fid, u64 *volatile_fid,
__u32 desired_access, __u32 create_disposition,
__u32 file_attributes, __u32 create_options,
- struct smb2_file_all_info *buf);
+ __u8 *oplock, struct smb2_file_all_info *buf);
extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_file_id, u64 volatile_file_id);
extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 42/45] CIFS: Move oplock break to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (40 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 41/45] CIFS: Process oplocks " Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:48 ` [PATCH 43/45] CIFS: Add oplock break support for SMB2 Pavel Shilovsky
` (3 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsglob.h | 4 ++++
fs/cifs/file.c | 7 +++----
fs/cifs/smb1ops.c | 10 ++++++++++
3 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 133cd0c..a8f424f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -178,6 +178,7 @@ struct cifs_readdata;
struct cifs_writedata;
struct cifs_io_parms;
struct cifs_search_info;
+struct cifsInodeInfo;
struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -329,6 +330,9 @@ struct smb_version_operations {
/* calculate a size of SMB message */
unsigned int (*calc_smb_size)(void *);
bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
+ /* send oplock break response */
+ int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
+ struct cifsInodeInfo *);
};
struct smb_version_values {
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index da9dc50..40230a7 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -3395,6 +3395,7 @@ void cifs_oplock_break(struct work_struct *work)
oplock_break);
struct inode *inode = cfile->dentry->d_inode;
struct cifsInodeInfo *cinode = CIFS_I(inode);
+ struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0;
if (inode && S_ISREG(inode->i_mode)) {
@@ -3422,10 +3423,8 @@ void cifs_oplock_break(struct work_struct *work)
* disconnected since oplock already released by the server
*/
if (!cfile->oplock_break_cancelled) {
- rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->fid.netfid,
- current->tgid, 0, 0, 0, 0,
- LOCKING_ANDX_OPLOCK_RELEASE, false,
- cinode->clientCanCacheRead ? 1 : 0);
+ rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
+ cinode);
cFYI(1, "Oplock release rc = %d", rc);
}
}
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 068d609..f55b2e3 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -863,6 +863,15 @@ cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
return CIFSFindClose(xid, tcon, fid->netfid);
}
+static int
+cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+ struct cifsInodeInfo *cinode)
+{
+ return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0,
+ LOCKING_ANDX_OPLOCK_RELEASE, false,
+ cinode->clientCanCacheRead ? 1 : 0);
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -922,6 +931,7 @@ struct smb_version_operations smb1_operations = {
.query_dir_next = cifs_query_dir_next,
.close_dir = cifs_close_dir,
.calc_smb_size = smbCalcSize,
+ .oplock_response = cifs_oplock_response,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 43/45] CIFS: Add oplock break support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (41 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 42/45] CIFS: Move oplock break to ops struct Pavel Shilovsky
@ 2012-07-18 15:48 ` Pavel Shilovsky
2012-07-18 15:49 ` [PATCH 44/45] CIFS: Move statfs to ops struct Pavel Shilovsky
` (2 subsequent siblings)
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:48 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2misc.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++-
fs/cifs/smb2ops.c | 19 +++++++++++-
fs/cifs/smb2pdu.c | 35 +++++++++++++++++++++++
fs/cifs/smb2pdu.h | 10 +++++++
fs/cifs/smb2proto.h | 5 +++
5 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 81fb162..15e0d8d 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -141,8 +141,8 @@ smb2_check_message(char *buf, unsigned int length)
}
if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
- if (hdr->Status == 0 ||
- pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2) {
+ if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
+ pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
/* error packets have 9 byte structure size */
cERROR(1, "Illegal response size %u for command %d",
le16_to_cpu(pdu->StructureSize2), command);
@@ -161,6 +161,8 @@ smb2_check_message(char *buf, unsigned int length)
if (4 + len != clc_len) {
cFYI(1, "Calculated size %u length %u mismatch mid %llu",
clc_len, 4 + len, mid);
+ if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
+ return 0; /* Windows 7 server returns 24 bytes more */
if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */
return 0; /* BB workaround Samba 3 bug SessSetup rsp */
return 1;
@@ -354,3 +356,72 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
CIFS_MOUNT_MAP_SPECIAL_CHR);
return to;
}
+
+bool
+smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
+{
+ struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
+ struct list_head *tmp, *tmp1, *tmp2;
+ struct cifs_ses *ses;
+ struct cifs_tcon *tcon;
+ struct cifsInodeInfo *cinode;
+ struct cifsFileInfo *cfile;
+
+ cFYI(1, "Checking for oplock break");
+
+ if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+ return false;
+
+ if (le16_to_cpu(rsp->StructureSize) !=
+ smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
+ return false;
+ }
+
+ cFYI(1, "oplock level 0x%d", rsp->OplockLevel);
+
+ /* look up tcon based on tid & uid */
+ spin_lock(&cifs_tcp_ses_lock);
+ list_for_each(tmp, &server->smb_ses_list) {
+ ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+ list_for_each(tmp1, &ses->tcon_list) {
+ tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+ cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+ spin_lock(&cifs_file_list_lock);
+ list_for_each(tmp2, &tcon->openFileList) {
+ cfile = list_entry(tmp2, struct cifsFileInfo,
+ tlist);
+ if (rsp->PersistentFid !=
+ cfile->fid.persistent_fid ||
+ rsp->VolatileFid !=
+ cfile->fid.volatile_fid)
+ continue;
+
+ cFYI(1, "file id match, oplock break");
+ cinode = CIFS_I(cfile->dentry->d_inode);
+
+ if (!cinode->clientCanCacheAll &&
+ rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
+ cfile->oplock_break_cancelled = true;
+ else
+ cfile->oplock_break_cancelled = false;
+
+ smb2_set_oplock_level(cinode,
+ rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+
+ queue_work(cifsiod_wq, &cfile->oplock_break);
+
+ spin_unlock(&cifs_file_list_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ return true;
+ }
+ spin_unlock(&cifs_file_list_lock);
+ spin_unlock(&cifs_tcp_ses_lock);
+ cFYI(1, "No matching file for oplock break");
+ return true;
+ }
+ }
+ spin_unlock(&cifs_tcp_ses_lock);
+ cFYI(1, "Can not process oplock break for non-existent connection");
+ return false;
+}
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 25f4263..99dbb8c 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -483,11 +483,24 @@ smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
return false;
- if (!length)
- add_credits(server, le16_to_cpu(hdr->CreditRequest), 0);
+ if (!length) {
+ spin_lock(&server->req_lock);
+ server->credits += le16_to_cpu(hdr->CreditRequest);
+ spin_unlock(&server->req_lock);
+ wake_up(&server->request_q);
+ }
return true;
}
+static int
+smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+ struct cifsInodeInfo *cinode)
+{
+ return SMB2_oplock_break(0, tcon, fid->persistent_fid,
+ fid->volatile_fid,
+ cinode->clientCanCacheRead ? 1 : 0);
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -505,6 +518,7 @@ struct smb_version_operations smb21_operations = {
.dump_detail = smb2_dump_detail,
.clear_stats = smb2_clear_stats,
.print_stats = smb2_print_stats,
+ .is_oplock_break = smb2_is_valid_oplock_break,
.need_neg = smb2_need_neg,
.negotiate = smb2_negotiate,
.negotiate_wsize = smb2_negotiate_wsize,
@@ -542,6 +556,7 @@ struct smb_version_operations smb21_operations = {
.close_dir = smb2_close_dir,
.calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending,
+ .oplock_response = smb2_oplock_response,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 58c1e91..a04917e 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1936,3 +1936,38 @@ SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
current->tgid, FILE_BASIC_INFORMATION, 1,
(void **)&buf, &size);
}
+
+int
+SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ __u8 oplock_level)
+{
+ int rc = 0, buf_type;
+ struct smb2_oplock_break *req = NULL;
+ struct kvec iov[1];
+
+ cFYI(1, "SMB2_oplock_break");
+ rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+
+ if (rc)
+ return rc;
+
+ req->VolatileFid = volatile_fid;
+ req->PersistentFid = persistent_fid;
+ req->OplockLevel = oplock_level;
+ req->hdr.CreditRequest = cpu_to_le16(1);
+
+ iov->iov_base = (char *)req;
+ /* 4 for rfc1002 length */
+ iov->iov_len = get_rfc1002_length(req) + 4;
+
+ rc = SendReceive2(xid, tcon->ses, iov, 1, &buf_type, CIFS_OBREAK_OP);
+ /* SMB2 buffer freed by function above */
+
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+ cFYI(1, "Send error in Oplock Break = %d", rc);
+ }
+
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index cd64385..0e5afb7 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -613,6 +613,16 @@ struct smb2_set_info_rsp {
__le16 StructureSize; /* Must be 2 */
} __packed;
+struct smb2_oplock_break {
+ struct smb2_hdr hdr;
+ __le16 StructureSize; /* Must be 24 */
+ __u8 OplockLevel;
+ __u8 Reserved;
+ __le32 Reserved2;
+ __u64 PersistentFid;
+ __u64 VolatileFid;
+} __packed;
+
/*
* PDU infolevel structure definitions
* BB consider moving to a different header
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index d18339f..de554b7 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -49,6 +49,8 @@ extern int smb2_setup_async_request(struct TCP_Server_Info *server,
struct kvec *iov, unsigned int nvec,
struct mid_q_entry **ret_mid);
extern void smb2_echo_request(struct work_struct *work);
+extern bool smb2_is_valid_oplock_break(char *buffer,
+ struct TCP_Server_Info *srv);
extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
struct smb2_file_all_info *src);
@@ -133,5 +135,8 @@ extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
FILE_BASIC_INFO *buf);
+extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+ const u64 persistent_fid, const u64 volatile_fid,
+ const __u8 oplock_level);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 44/45] CIFS: Move statfs to ops struct
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (42 preceding siblings ...)
2012-07-18 15:48 ` [PATCH 43/45] CIFS: Add oplock break support for SMB2 Pavel Shilovsky
@ 2012-07-18 15:49 ` Pavel Shilovsky
2012-07-18 15:49 ` [PATCH 45/45] CIFS: Add statfs support for SMB2 Pavel Shilovsky
2012-08-03 15:14 ` [PATCH 00/45] SMB2 base operation support Steve French
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:49 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/cifsfs.c | 29 ++++-------------------------
fs/cifs/cifsglob.h | 5 +++++
fs/cifs/smb1ops.c | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 43 insertions(+), 25 deletions(-)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 65f8b05..4dde869 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -51,7 +51,6 @@
#ifdef CONFIG_CIFS_SMB2
#include "smb2pdu.h"
#endif
-#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
int cifsFYI = 0;
int cifsERROR = 1;
@@ -162,13 +161,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
struct super_block *sb = dentry->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
- int rc = -EOPNOTSUPP;
+ struct TCP_Server_Info *server = tcon->ses->server;
unsigned int xid;
+ int rc = 0;
xid = get_xid();
- buf->f_type = CIFS_MAGIC_NUMBER;
-
/*
* PATH_MAX may be too long - it would presumably be total path,
* but note that some servers (includinng Samba 3) have a shorter
@@ -180,27 +178,8 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_files = 0; /* undefined */
buf->f_ffree = 0; /* unlimited */
- /*
- * We could add a second check for a QFS Unix capability bit
- */
- if ((tcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
- rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
-
- /*
- * Only need to call the old QFSInfo if failed on newer one,
- * e.g. by OS/2.
- **/
- if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
- rc = CIFSSMBQFSInfo(xid, tcon, buf);
-
- /*
- * Some old Windows servers also do not support level 103, retry with
- * older level one if old server failed the previous call or we
- * bypassed it because we detected that this was an older LANMAN sess
- */
- if (rc)
- rc = SMBOldQFSInfo(xid, tcon, buf);
+ if (server->ops->queryfs)
+ rc = server->ops->queryfs(xid, tcon, buf);
free_xid(xid);
return 0;
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a8f424f..46bbbe4 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -32,6 +32,8 @@
#include "smb2pdu.h"
#endif
+#define CIFS_MAGIC_NUMBER 0xFF534D42 /* the first four bytes of SMB PDUs */
+
/*
* The sizes of various internal tables and strings
*/
@@ -333,6 +335,9 @@ struct smb_version_operations {
/* send oplock break response */
int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
struct cifsInodeInfo *);
+ /* query remote filesystem */
+ int (*queryfs)(const unsigned int, struct cifs_tcon *,
+ struct kstatfs *);
};
struct smb_version_values {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index f55b2e3..f6c7a1c 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -18,6 +18,7 @@
*/
#include <linux/pagemap.h>
+#include <linux/vfs.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
@@ -872,6 +873,38 @@ cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
cinode->clientCanCacheRead ? 1 : 0);
}
+static int
+cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+ struct kstatfs *buf)
+{
+ int rc = -EOPNOTSUPP;
+
+ buf->f_type = CIFS_MAGIC_NUMBER;
+
+ /*
+ * We could add a second check for a QFS Unix capability bit
+ */
+ if ((tcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
+ rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
+
+ /*
+ * Only need to call the old QFSInfo if failed on newer one,
+ * e.g. by OS/2.
+ **/
+ if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
+ rc = CIFSSMBQFSInfo(xid, tcon, buf);
+
+ /*
+ * Some old Windows servers also do not support level 103, retry with
+ * older level one if old server failed the previous call or we
+ * bypassed it because we detected that this was an older LANMAN sess
+ */
+ if (rc)
+ rc = SMBOldQFSInfo(xid, tcon, buf);
+ return rc;
+}
+
struct smb_version_operations smb1_operations = {
.send_cancel = send_nt_cancel,
.compare_fids = cifs_compare_fids,
@@ -932,6 +965,7 @@ struct smb_version_operations smb1_operations = {
.close_dir = cifs_close_dir,
.calc_smb_size = smbCalcSize,
.oplock_response = cifs_oplock_response,
+ .queryfs = cifs_queryfs,
};
struct smb_version_values smb1_values = {
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* [PATCH 45/45] CIFS: Add statfs support for SMB2
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (43 preceding siblings ...)
2012-07-18 15:49 ` [PATCH 44/45] CIFS: Move statfs to ops struct Pavel Shilovsky
@ 2012-07-18 15:49 ` Pavel Shilovsky
2012-08-03 15:14 ` [PATCH 00/45] SMB2 base operation support Steve French
45 siblings, 0 replies; 74+ messages in thread
From: Pavel Shilovsky @ 2012-07-18 15:49 UTC (permalink / raw)
To: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Signed-off-by: Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
---
fs/cifs/smb2glob.h | 2 +
fs/cifs/smb2ops.c | 22 ++++++++++++++
fs/cifs/smb2pdu.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++
fs/cifs/smb2pdu.h | 19 ++++++++++++
fs/cifs/smb2proto.h | 3 ++
5 files changed, 127 insertions(+), 0 deletions(-)
diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 05d429b..7c0e214 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -23,6 +23,8 @@
#ifndef _SMB2_GLOB_H
#define _SMB2_GLOB_H
+#define SMB2_MAGIC_NUMBER 0xFE534D42
+
/*
*****************************************************************
* Constants go here
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 99dbb8c..a1333d2 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -17,12 +17,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/vfs.h>
#include "cifsglob.h"
#include "smb2pdu.h"
#include "smb2proto.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smb2status.h"
+#include "smb2glob.h"
static int
change_conf(struct TCP_Server_Info *server)
@@ -501,6 +503,25 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
cinode->clientCanCacheRead ? 1 : 0);
}
+static int
+smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+ struct kstatfs *buf)
+{
+ int rc;
+ u64 persistent_fid, volatile_fid;
+ __le16 srch_path = 0; /* Null - open root of share */
+ u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+
+ rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid,
+ FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
+ if (rc)
+ return rc;
+ buf->f_type = SMB2_MAGIC_NUMBER;
+ rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf);
+ SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+ return rc;
+}
+
struct smb_version_operations smb21_operations = {
.setup_request = smb2_setup_request,
.setup_async_request = smb2_setup_async_request,
@@ -557,6 +578,7 @@ struct smb_version_operations smb21_operations = {
.calc_smb_size = smb2_calc_size,
.is_status_pending = smb2_is_status_pending,
.oplock_response = smb2_oplock_response,
+ .queryfs = smb2_queryfs,
};
struct smb_version_values smb21_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index a04917e..61a4b88 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1971,3 +1971,84 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
return rc;
}
+
+static void
+copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
+ struct kstatfs *kst)
+{
+ kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
+ le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
+ kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
+ kst->f_bfree = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
+ kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+ return;
+}
+
+static int
+build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
+ int outbuf_len, u64 persistent_fid, u64 volatile_fid)
+{
+ int rc;
+ struct smb2_query_info_req *req;
+
+ cFYI(1, "Query FSInfo level %d", level);
+
+ if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+ return -EIO;
+
+ rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req);
+ if (rc)
+ return rc;
+
+ req->InfoType = SMB2_O_INFO_FILESYSTEM;
+ req->FileInfoClass = level;
+ req->PersistentFileId = persistent_fid;
+ req->VolatileFileId = volatile_fid;
+ /* 4 for rfc1002 length field and 1 for pad */
+ req->InputBufferOffset =
+ cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
+ req->OutputBufferLength = cpu_to_le32(
+ outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
+
+ iov->iov_base = (char *)req;
+ /* 4 for rfc1002 length field */
+ iov->iov_len = get_rfc1002_length(req) + 4;
+ return 0;
+}
+
+int
+SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
+{
+ struct smb2_query_info_rsp *rsp = NULL;
+ struct kvec iov;
+ int rc = 0;
+ int resp_buftype;
+ struct cifs_ses *ses = tcon->ses;
+ struct smb2_fs_full_size_info *info = NULL;
+
+ rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
+ sizeof(struct smb2_fs_full_size_info),
+ persistent_fid, volatile_fid);
+ if (rc)
+ return rc;
+
+ rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+ if (rc) {
+ cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+ goto qinf_exit;
+ }
+ rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+
+ info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
+ le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
+ rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+ le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+ sizeof(struct smb2_fs_full_size_info));
+ if (!rc)
+ copy_fs_info_to_kstatfs(info, fsdata);
+
+qinf_exit:
+ free_rsp_buf(resp_buftype, iov.iov_base);
+ return rc;
+}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 0e5afb7..30c7d73 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -628,6 +628,25 @@ struct smb2_oplock_break {
* BB consider moving to a different header
*/
+/* File System Information Classes */
+#define FS_VOLUME_INFORMATION 1 /* Query */
+#define FS_LABEL_INFORMATION 2 /* Set */
+#define FS_SIZE_INFORMATION 3 /* Query */
+#define FS_DEVICE_INFORMATION 4 /* Query */
+#define FS_ATTRIBUTE_INFORMATION 5 /* Query */
+#define FS_CONTROL_INFORMATION 6 /* Query, Set */
+#define FS_FULL_SIZE_INFORMATION 7 /* Query */
+#define FS_OBJECT_ID_INFORMATION 8 /* Query, Set */
+#define FS_DRIVER_PATH_INFORMATION 9 /* Query */
+
+struct smb2_fs_full_size_info {
+ __le64 TotalAllocationUnits;
+ __le64 CallerAvailableAllocationUnits;
+ __le64 ActualAvailableAllocationUnits;
+ __le32 SectorsPerAllocationUnit;
+ __le32 BytesPerSector;
+} __packed;
+
/* partial list of QUERY INFO levels */
#define FILE_DIRECTORY_INFORMATION 1
#define FILE_FULL_DIRECTORY_INFORMATION 2
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index de554b7..a73a963 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -138,5 +138,8 @@ extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
const u64 persistent_fid, const u64 volatile_fid,
const __u8 oplock_level);
+extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+ u64 persistent_file_id, u64 volatile_file_id,
+ struct kstatfs *FSData);
#endif /* _SMB2PROTO_H */
--
1.7.1
^ permalink raw reply related [flat|nested] 74+ messages in thread
* Re: [PATCH 00/45] SMB2 base operation support
[not found] ` <1342626541-29872-1-git-send-email-pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
` (44 preceding siblings ...)
2012-07-18 15:49 ` [PATCH 45/45] CIFS: Add statfs support for SMB2 Pavel Shilovsky
@ 2012-08-03 15:14 ` Steve French
45 siblings, 0 replies; 74+ messages in thread
From: Steve French @ 2012-08-03 15:14 UTC (permalink / raw)
To: Pavel Shilovsky; +Cc: linux-cifs-u79uwXL29TY76Z2rM5mHXA
Now that I have also had a chance to rereview the remainder of the
series, and retest these. I merged the last part of Pavel's "smb2
basic" support into cifs-2.6.git for-next (the first part of the
series below is already upstream, as is the earlier smb2 transport
enablement and cifs common code restructuring). Even though it tests
ok I plan to leave the SMB2 support as CONFIG_BROKEN until after the
testing at the annual Storage Developer Conference (SMB2 Plugfest)
next month, unless I get more test feedback.
Other near term items:
Jeff noted that we need to merge the patch for default security
mechanism upgrade for cifs, and Jeff has a series of 5 socket handling
patches that Pavel found a problem with (that presumably is a bug in
Windows not in the Linux kernel client - but need to investigate
more). In addition for SMB2 there are also three sparse warnings in
Pavel's code that I want to eliminate.
On Wed, Jul 18, 2012 at 10:48 AM, Pavel Shilovsky <pshilovsky-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> This patchset is the second part of big SMB2 merge (after smb2-mount). It adds SMB2 support for
> file and inode operation as well as rewrites existing part of their code to make it use ops
> server struct of protocol specific callbacks.
>
> The patchset is tested by cthon tests: basic and general parts.
>
> Pavel Shilovsky (45):
> CIFS: Make CAP_* checks protocol independent
> CIFS: Simpliify cifs_mkdir call
> CIFS: Separate protocol specific part from mkdir
> CIFS: Add SMB2 support for mkdir operation
> CIFS: Move rmdir code to ops struct
> CIFS: Add SMB2 support for rmdir
> CIFS: Protect i_nlink from being negative
> CIFS: Move unlink code to ops struct
> CIFS: Add SMB2 support for unlink
> CIFS: Replace netfid with cifs_fid struct in cifsFileInfo
> CIFS: Move open code to ops struct
> CIFS: Move close code to ops struct
> CIFS: Add open/close file support for SMB2
> CIFS: Move guery file info code to ops struct
> CIFS: Add SMB2 support for query_file_info
> CIFS: Move create code use ops struct
> CIFS: Move reopen code to ops struct
> CIFS: Make flush code use ops struct
> CIFS: Add SMB2 support for flush
> CIFS: Move r/wsize negotiating to ops struct
> CIFS: Add SMB2 r/wsize negotiating
> CIFS: Move async read to ops struct
> CIFS: Add SMB2 support for cifs_iovec_read
> CIFS: Move async write to ops struct
> CIFS: Add SMB2 support for cifs_iovec_write
> CIFS: Move readpage code to ops struct
> CIFS: Add readpage support for SMB2
> CIFS: Move writepage to ops struct
> CIFS: Add writepage support for SMB2
> CIFS: Enable signing in SMB2
> CIFS: Move rename to ops struct
> CIFS: Add SMB2 support for rename operation
> CIFS: Move hardlink to ops struct
> CIFS: Add SMB2 support for hardlink operation
> CIFS: Move set_file_size to ops struct
> CIFS: Add SMB2 support for set_file_size
> CIFS: Move set_file_info to ops struct
> CIFS: Add set_file_info support for SMB2
> CIFS: Move readdir code to ops struct
> CIFS: Add readdir support for SMB2
> CIFS: Process oplocks for SMB2
> CIFS: Move oplock break to ops struct
> CIFS: Add oplock break support for SMB2
> CIFS: Move statfs to ops struct
> CIFS: Add statfs support for SMB2
>
> fs/cifs/Kconfig | 1 +
> fs/cifs/Makefile | 2 +-
> fs/cifs/cifsacl.c | 2 +-
> fs/cifs/cifsencrypt.c | 30 ++-
> fs/cifs/cifsfs.c | 31 +--
> fs/cifs/cifsglob.h | 241 ++++++++++++-
> fs/cifs/cifsproto.h | 96 ++----
> fs/cifs/cifssmb.c | 171 ++++-----
> fs/cifs/connect.c | 154 +-------
> fs/cifs/dir.c | 108 +++---
> fs/cifs/file.c | 473 +++++++++++++-----------
> fs/cifs/inode.c | 652 ++++++++++++++++----------------
> fs/cifs/ioctl.c | 13 +-
> fs/cifs/link.c | 80 +++--
> fs/cifs/misc.c | 2 +-
> fs/cifs/netmisc.c | 3 +-
> fs/cifs/readdir.c | 179 +++++----
> fs/cifs/smb1ops.c | 351 +++++++++++++++++-
> fs/cifs/smb2file.c | 106 ++++++
> fs/cifs/smb2glob.h | 14 +
> fs/cifs/smb2inode.c | 137 +++++++-
> fs/cifs/smb2maperror.c | 3 +-
> fs/cifs/smb2misc.c | 86 ++++-
> fs/cifs/smb2ops.c | 267 +++++++++++++-
> fs/cifs/smb2pdu.c | 957 ++++++++++++++++++++++++++++++++++++++++++++++-
> fs/cifs/smb2pdu.h | 178 +++++++++
> fs/cifs/smb2proto.h | 71 ++++-
> fs/cifs/smb2transport.c | 157 ++++++++-
> fs/cifs/transport.c | 24 +-
> 29 files changed, 3499 insertions(+), 1090 deletions(-)
> create mode 100644 fs/cifs/smb2file.c
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Thanks,
Steve
^ permalink raw reply [flat|nested] 74+ messages in thread