aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2012-09-28 13:21:14 -0400
committerSteve French <smfrench@gmail.com>2012-09-28 16:32:28 -0400
commitc052e2b423f3eabe9f3f32e60744afa5cf26f6b9 (patch)
tree03530fe0622d19a7d4e8d80e4e17e7681e95dc42 /fs/cifs
parentf065fd099fc475333fc7a55677a7f64764445d55 (diff)
cifs: obtain file access during backup intent lookup (resend)
Rebased and resending the patch. Path based queries can fail for lack of access, especially during lookup during open. open itself would actually succeed becasue of back up intent bit but queries (either path or file handle based) do not have a means to specifiy backup intent bit. So query the file info during lookup using trans2 / findfirst / file_id_full_dir_info to obtain file info as well as file_id/inode value. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Acked-by: Jeff Layton <jlayton@samba.org> Signed-off-by: Steve French <smfrench@gmail.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifsproto.h6
-rw-r--r--fs/cifs/cifssmb.c43
-rw-r--r--fs/cifs/inode.c64
-rw-r--r--fs/cifs/readdir.c2
-rw-r--r--fs/cifs/smb1ops.c6
5 files changed, 80 insertions, 41 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 09ea6321c55a..5144e9fbeb8c 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -140,6 +140,8 @@ void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
140extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, 140extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr,
141 FILE_UNIX_BASIC_INFO *info, 141 FILE_UNIX_BASIC_INFO *info,
142 struct cifs_sb_info *cifs_sb); 142 struct cifs_sb_info *cifs_sb);
143extern void cifs_dir_info_to_fattr(struct cifs_fattr *, FILE_DIRECTORY_INFO *,
144 struct cifs_sb_info *);
143extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr); 145extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
144extern struct inode *cifs_iget(struct super_block *sb, 146extern struct inode *cifs_iget(struct super_block *sb,
145 struct cifs_fattr *fattr); 147 struct cifs_fattr *fattr);
@@ -216,10 +218,10 @@ extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
216 const struct nls_table *); 218 const struct nls_table *);
217 219
218extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, 220extern int CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
219 const char *searchName, const struct nls_table *nls_codepage, 221 const char *searchName, struct cifs_sb_info *cifs_sb,
220 __u16 *searchHandle, __u16 search_flags, 222 __u16 *searchHandle, __u16 search_flags,
221 struct cifs_search_info *psrch_inf, 223 struct cifs_search_info *psrch_inf,
222 int map, const char dirsep); 224 bool msearch);
223 225
224extern int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon, 226extern int CIFSFindNext(const unsigned int xid, struct cifs_tcon *tcon,
225 __u16 searchHandle, __u16 search_flags, 227 __u16 searchHandle, __u16 search_flags,
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 88bbb3ef95b3..76d0d2998850 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -4214,10 +4214,9 @@ UnixQPathInfoRetry:
4214/* xid, tcon, searchName and codepage are input parms, rest are returned */ 4214/* xid, tcon, searchName and codepage are input parms, rest are returned */
4215int 4215int
4216CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon, 4216CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
4217 const char *searchName, 4217 const char *searchName, struct cifs_sb_info *cifs_sb,
4218 const struct nls_table *nls_codepage,
4219 __u16 *pnetfid, __u16 search_flags, 4218 __u16 *pnetfid, __u16 search_flags,
4220 struct cifs_search_info *psrch_inf, int remap, const char dirsep) 4219 struct cifs_search_info *psrch_inf, bool msearch)
4221{ 4220{
4222/* level 257 SMB_ */ 4221/* level 257 SMB_ */
4223 TRANSACTION2_FFIRST_REQ *pSMB = NULL; 4222 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -4225,8 +4224,9 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tcon *tcon,
4225 T2_FFIRST_RSP_PARMS *parms; 4224 T2_FFIRST_RSP_PARMS *parms;
4226 int rc = 0; 4225 int rc = 0;
4227 int bytes_returned = 0; 4226 int bytes_returned = 0;
4228 int name_len; 4227 int name_len, remap;
4229 __u16 params, byte_count; 4228 __u16 params, byte_count;
4229 struct nls_table *nls_codepage;
4230 4230
4231 cFYI(1, "In FindFirst for %s", searchName); 4231 cFYI(1, "In FindFirst for %s", searchName);
4232 4232
@@ -4236,6 +4236,9 @@ findFirstRetry:
4236 if (rc) 4236 if (rc)
4237 return rc; 4237 return rc;
4238 4238
4239 nls_codepage = cifs_sb->local_nls;
4240 remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
4241
4239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { 4242 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4240 name_len = 4243 name_len =
4241 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName, 4244 cifsConvertToUTF16((__le16 *) pSMB->FileName, searchName,
@@ -4244,24 +4247,29 @@ findFirstRetry:
4244 it got remapped to 0xF03A as if it were part of the 4247 it got remapped to 0xF03A as if it were part of the
4245 directory name instead of a wildcard */ 4248 directory name instead of a wildcard */
4246 name_len *= 2; 4249 name_len *= 2;
4247 pSMB->FileName[name_len] = dirsep; 4250 if (msearch) {
4248 pSMB->FileName[name_len+1] = 0; 4251 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4249 pSMB->FileName[name_len+2] = '*'; 4252 pSMB->FileName[name_len+1] = 0;
4250 pSMB->FileName[name_len+3] = 0; 4253 pSMB->FileName[name_len+2] = '*';
4251 name_len += 4; /* now the trailing null */ 4254 pSMB->FileName[name_len+3] = 0;
4252 pSMB->FileName[name_len] = 0; /* null terminate just in case */ 4255 name_len += 4; /* now the trailing null */
4253 pSMB->FileName[name_len+1] = 0; 4256 /* null terminate just in case */
4254 name_len += 2; 4257 pSMB->FileName[name_len] = 0;
4258 pSMB->FileName[name_len+1] = 0;
4259 name_len += 2;
4260 }
4255 } else { /* BB add check for overrun of SMB buf BB */ 4261 } else { /* BB add check for overrun of SMB buf BB */
4256 name_len = strnlen(searchName, PATH_MAX); 4262 name_len = strnlen(searchName, PATH_MAX);
4257/* BB fix here and in unicode clause above ie 4263/* BB fix here and in unicode clause above ie
4258 if (name_len > buffersize-header) 4264 if (name_len > buffersize-header)
4259 free buffer exit; BB */ 4265 free buffer exit; BB */
4260 strncpy(pSMB->FileName, searchName, name_len); 4266 strncpy(pSMB->FileName, searchName, name_len);
4261 pSMB->FileName[name_len] = dirsep; 4267 if (msearch) {
4262 pSMB->FileName[name_len+1] = '*'; 4268 pSMB->FileName[name_len] = CIFS_DIR_SEP(cifs_sb);
4263 pSMB->FileName[name_len+2] = 0; 4269 pSMB->FileName[name_len+1] = '*';
4264 name_len += 3; 4270 pSMB->FileName[name_len+2] = 0;
4271 name_len += 3;
4272 }
4265 } 4273 }
4266 4274
4267 params = 12 + name_len /* includes null */ ; 4275 params = 12 + name_len /* includes null */ ;
@@ -4349,7 +4357,8 @@ findFirstRetry:
4349 psrch_inf->last_entry = psrch_inf->srch_entries_start + 4357 psrch_inf->last_entry = psrch_inf->srch_entries_start +
4350 lnoff; 4358 lnoff;
4351 4359
4352 *pnetfid = parms->SearchHandle; 4360 if (pnetfid)
4361 *pnetfid = parms->SearchHandle;
4353 } else { 4362 } else {
4354 cifs_buf_release(pSMB); 4363 cifs_buf_release(pSMB);
4355 } 4364 }
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 3d155875f446..afdff79651f1 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -607,7 +607,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
607 FILE_ALL_INFO *data, struct super_block *sb, int xid, 607 FILE_ALL_INFO *data, struct super_block *sb, int xid,
608 const __u16 *fid) 608 const __u16 *fid)
609{ 609{
610 int rc = 0, tmprc; 610 bool validinum = false;
611 __u16 srchflgs;
612 int rc = 0, tmprc = ENOSYS;
611 struct cifs_tcon *tcon; 613 struct cifs_tcon *tcon;
612 struct TCP_Server_Info *server; 614 struct TCP_Server_Info *server;
613 struct tcon_link *tlink; 615 struct tcon_link *tlink;
@@ -615,6 +617,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
615 char *buf = NULL; 617 char *buf = NULL;
616 bool adjust_tz = false; 618 bool adjust_tz = false;
617 struct cifs_fattr fattr; 619 struct cifs_fattr fattr;
620 struct cifs_search_info *srchinf = NULL;
618 621
619 tlink = cifs_sb_tlink(cifs_sb); 622 tlink = cifs_sb_tlink(cifs_sb);
620 if (IS_ERR(tlink)) 623 if (IS_ERR(tlink))
@@ -653,9 +656,38 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
653 } else if (rc == -EREMOTE) { 656 } else if (rc == -EREMOTE) {
654 cifs_create_dfs_fattr(&fattr, sb); 657 cifs_create_dfs_fattr(&fattr, sb);
655 rc = 0; 658 rc = 0;
656 } else { 659 } else if (rc == -EACCES && backup_cred(cifs_sb)) {
660 srchinf = kzalloc(sizeof(struct cifs_search_info),
661 GFP_KERNEL);
662 if (srchinf == NULL) {
663 rc = -ENOMEM;
664 goto cgii_exit;
665 }
666
667 srchinf->endOfSearch = false;
668 srchinf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO;
669
670 srchflgs = CIFS_SEARCH_CLOSE_ALWAYS |
671 CIFS_SEARCH_CLOSE_AT_END |
672 CIFS_SEARCH_BACKUP_SEARCH;
673
674 rc = CIFSFindFirst(xid, tcon, full_path,
675 cifs_sb, NULL, srchflgs, srchinf, false);
676 if (!rc) {
677 data =
678 (FILE_ALL_INFO *)srchinf->srch_entries_start;
679
680 cifs_dir_info_to_fattr(&fattr,
681 (FILE_DIRECTORY_INFO *)data, cifs_sb);
682 fattr.cf_uniqueid = le64_to_cpu(
683 ((SEARCH_ID_FULL_DIR_INFO *)data)->UniqueId);
684 validinum = true;
685
686 cifs_buf_release(srchinf->ntwrk_buf_start);
687 }
688 kfree(srchinf);
689 } else
657 goto cgii_exit; 690 goto cgii_exit;
658 }
659 691
660 /* 692 /*
661 * If an inode wasn't passed in, then get the inode number 693 * If an inode wasn't passed in, then get the inode number
@@ -666,23 +698,21 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
666 */ 698 */
667 if (*inode == NULL) { 699 if (*inode == NULL) {
668 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { 700 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
669 if (server->ops->get_srv_inum) 701 if (validinum == false) {
670 tmprc = server->ops->get_srv_inum(xid, tcon, 702 if (server->ops->get_srv_inum)
671 cifs_sb, full_path, &fattr.cf_uniqueid, 703 tmprc = server->ops->get_srv_inum(xid,
672 data); 704 tcon, cifs_sb, full_path,
673 else 705 &fattr.cf_uniqueid, data);
674 tmprc = -ENOSYS; 706 if (tmprc) {
675 if (tmprc || !fattr.cf_uniqueid) { 707 cFYI(1, "GetSrvInodeNum rc %d", tmprc);
676 cFYI(1, "GetSrvInodeNum rc %d", tmprc); 708 fattr.cf_uniqueid = iunique(sb, ROOT_I);
677 fattr.cf_uniqueid = iunique(sb, ROOT_I); 709 cifs_autodisable_serverino(cifs_sb);
678 cifs_autodisable_serverino(cifs_sb); 710 }
679 } 711 }
680 } else { 712 } else
681 fattr.cf_uniqueid = iunique(sb, ROOT_I); 713 fattr.cf_uniqueid = iunique(sb, ROOT_I);
682 } 714 } else
683 } else {
684 fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; 715 fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
685 }
686 716
687 /* query for SFU type info if supported and needed */ 717 /* query for SFU type info if supported and needed */
688 if (fattr.cf_cifsattrs & ATTR_SYSTEM && 718 if (fattr.cf_cifsattrs & ATTR_SYSTEM &&
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index b0f4a428398d..f9b5d3d6cf33 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -151,7 +151,7 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
151 } 151 }
152} 152}
153 153
154static void 154void
155cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, 155cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info,
156 struct cifs_sb_info *cifs_sb) 156 struct cifs_sb_info *cifs_sb)
157{ 157{
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 42dccbb57c40..56cc4be87807 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -837,10 +837,8 @@ cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
837 struct cifs_fid *fid, __u16 search_flags, 837 struct cifs_fid *fid, __u16 search_flags,
838 struct cifs_search_info *srch_inf) 838 struct cifs_search_info *srch_inf)
839{ 839{
840 return CIFSFindFirst(xid, tcon, path, cifs_sb->local_nls, 840 return CIFSFindFirst(xid, tcon, path, cifs_sb,
841 &fid->netfid, search_flags, srch_inf, 841 &fid->netfid, search_flags, srch_inf, true);
842 cifs_sb->mnt_cifs_flags &
843 CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
844} 842}
845 843
846static int 844static int