@@ -140,6 +140,8 @@ extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode,
extern int cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
struct cifsFileInfo **ret_file);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
+extern int cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
+ struct cifsFileInfo **ret_file);
extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server);
extern int decode_negTokenInit(unsigned char *security_blob, int length,
struct TCP_Server_Info *server);
@@ -2008,6 +2008,42 @@ cifs_get_writable_path(struct cifs_tcon *tcon, const char *name,
return -ENOENT;
}
+int
+cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
+ struct cifsFileInfo **ret_file)
+{
+ struct list_head *tmp;
+ struct cifsFileInfo *cfile;
+ struct cifsInodeInfo *cinode;
+ char *full_path;
+
+ *ret_file = NULL;
+
+ spin_lock(&tcon->open_file_lock);
+ list_for_each(tmp, &tcon->openFileList) {
+ cfile = list_entry(tmp, struct cifsFileInfo,
+ tlist);
+ full_path = build_path_from_dentry(cfile->dentry);
+ if (full_path == NULL) {
+ spin_unlock(&tcon->open_file_lock);
+ return -ENOMEM;
+ }
+ if (strcmp(full_path, name)) {
+ kfree(full_path);
+ continue;
+ }
+
+ kfree(full_path);
+ cinode = CIFS_I(d_inode(cfile->dentry));
+ spin_unlock(&tcon->open_file_lock);
+ *ret_file = find_readable_file(cinode, 0);
+ return *ret_file ? 0 : -ENOENT;
+ }
+
+ spin_unlock(&tcon->open_file_lock);
+ return -ENOENT;
+}
+
static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
{
struct address_space *mapping = page->mapping;
@@ -125,15 +125,31 @@ smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
rqst[num_rqst].rq_iov = qi_iov;
rqst[num_rqst].rq_nvec = 1;
- rc = SMB2_query_info_init(tcon, &rqst[num_rqst], COMPOUND_FID,
- COMPOUND_FID, FILE_ALL_INFORMATION,
+ if (cfile)
+ rc = SMB2_query_info_init(tcon, &rqst[num_rqst],
+ cfile->fid.persistent_fid,
+ cfile->fid.volatile_fid,
+ FILE_ALL_INFORMATION,
SMB2_O_INFO_FILE, 0,
sizeof(struct smb2_file_all_info) +
PATH_MAX * 2, 0, NULL);
+ else {
+ rc = SMB2_query_info_init(tcon, &rqst[num_rqst],
+ COMPOUND_FID,
+ COMPOUND_FID,
+ FILE_ALL_INFORMATION,
+ SMB2_O_INFO_FILE, 0,
+ sizeof(struct smb2_file_all_info) +
+ PATH_MAX * 2, 0, NULL);
+ if (!rc) {
+ smb2_set_next_command(tcon, &rqst[num_rqst]);
+ smb2_set_related(&rqst[num_rqst]);
+ }
+ }
+
if (rc)
goto finished;
- smb2_set_next_command(tcon, &rqst[num_rqst]);
- smb2_set_related(&rqst[num_rqst++]);
+ num_rqst++;
trace_smb3_query_info_compound_enter(xid, ses->Suid, tcon->tid,
full_path);
break;
@@ -421,6 +437,7 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
__u32 create_options = 0;
struct cifs_fid fid;
bool no_cached_open = tcon->nohandlecache;
+ struct cifsFileInfo *cfile;
*adjust_tz = false;
*symlink = false;
@@ -452,9 +469,10 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;
+ cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
FILE_READ_ATTRIBUTES, FILE_OPEN, create_options,
- smb2_data, SMB2_OP_QUERY_INFO, NULL);
+ smb2_data, SMB2_OP_QUERY_INFO, cfile);
if (rc == -EOPNOTSUPP) {
*symlink = true;
create_options |= OPEN_REPARSE_POINT;
and convert smb2_query_path_info() to use it. This will eliminate the need for a SMB2_Create when we already have an open handle that can be used. This will also prevent a oplock break in case the other handle holds a lease. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/cifsproto.h | 2 ++ fs/cifs/file.c | 36 ++++++++++++++++++++++++++++++++++++ fs/cifs/smb2inode.c | 28 +++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 5 deletions(-)