From patchwork Wed Jul 25 22:45:04 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shirish Pargaonkar X-Patchwork-Id: 1239791 Return-Path: X-Original-To: patchwork-cifs-client@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id E96D5DFFCD for ; Wed, 25 Jul 2012 22:33:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751278Ab2GYWdH (ORCPT ); Wed, 25 Jul 2012 18:33:07 -0400 Received: from mail-pb0-f46.google.com ([209.85.160.46]:49234 "EHLO mail-pb0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751133Ab2GYWdF (ORCPT ); Wed, 25 Jul 2012 18:33:05 -0400 Received: by pbbrp8 with SMTP id rp8so2107003pbb.19 for ; Wed, 25 Jul 2012 15:33:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer; bh=djcWRtBNRfc18G32CXlwl85k4ovcjSeI7S1Qk7HeaUI=; b=r/KlYpLKzqlz89HNV8FvsWS9Tp7cEy1ZONmn4tJejhoaHZKUszXb1wpCe0Q06xof8w 6xOJb7Ui1bVI7IUXaGQNregvLZSYqEZdRXVgFkDh6Y9CNiG1zgzN1LZ38PLp59+L46ZA 5OEt+sWE9p3q1z4XL3Ez26XsVSpQ7YQx6U0d8UxMuKrN/E6XGaI0pfQ9QXo60C8ZyFUI N/OVnjxqcZoSjO7+CRYjVsgQxdbaVLaSchwQbZf9hLxAO7gwQquadgiyTDfRc606VRSF AXhKT10T3tzsn4Gvcd4ueiHrI7Mv0Z+4TGUAmn1BOCQNcCbyWJ0zebq/8aH3aCprbPkh fPRg== Received: by 10.68.197.70 with SMTP id is6mr56600829pbc.64.1343255584816; Wed, 25 Jul 2012 15:33:04 -0700 (PDT) Received: from localhost ([32.97.110.50]) by mx.google.com with ESMTPS id ph1sm15163218pbb.45.2012.07.25.15.33.04 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 25 Jul 2012 15:33:04 -0700 (PDT) From: shirishpargaonkar@gmail.com To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, tugosavi@in.ibm.com, Shirish Pargaonkar Subject: [PATCH v2] cifs: obtain file access during backup intent lookup Date: Wed, 25 Jul 2012 17:45:04 -0500 Message-Id: <1343256304-4735-1-git-send-email-shirishpargaonkar@gmail.com> X-Mailer: git-send-email 1.6.0.2 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org From: Shirish Pargaonkar path based querries can fail for lack of access, especially during lookup during open. open itself would actually succeed becasue of back up intent bit but querries (either path or file handle based) do not have a means to specifiy backup intent bit. So querry the file info during lookup using trans2 / findfirst2 / file_id_full_ir_info to obtain file info as well as file_id/inode value. Signed-off-by: Shirish Pargaonkar Reported-by: Tushar Gosavi --- fs/cifs/cifssmb.c | 38 +++++++++++++++++------------ fs/cifs/inode.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 18 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4ee522b..f059c0a 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -4257,7 +4257,7 @@ CIFSFindFirst(const int xid, struct cifs_tcon *tcon, int rc = 0; int bytes_returned = 0; int name_len; - __u16 params, byte_count; + __u16 params, byte_count, ffattrs; cFYI(1, "In FindFirst for %s", searchName); @@ -4275,27 +4275,35 @@ findFirstRetry: it got remapped to 0xF03A as if it were part of the directory name instead of a wildcard */ name_len *= 2; - pSMB->FileName[name_len] = dirsep; - pSMB->FileName[name_len+1] = 0; - pSMB->FileName[name_len+2] = '*'; - pSMB->FileName[name_len+3] = 0; - name_len += 4; /* now the trailing null */ - pSMB->FileName[name_len] = 0; /* null terminate just in case */ - pSMB->FileName[name_len+1] = 0; - name_len += 2; + if (dirsep) { + pSMB->FileName[name_len] = dirsep; + pSMB->FileName[name_len+1] = 0; + pSMB->FileName[name_len+2] = '*'; + pSMB->FileName[name_len+3] = 0; + name_len += 4; /* now the trailing null */ + /* null terminate just in case */ + pSMB->FileName[name_len] = 0; + pSMB->FileName[name_len+1] = 0; + name_len += 2; + } } else { /* BB add check for overrun of SMB buf BB */ name_len = strnlen(searchName, PATH_MAX); /* BB fix here and in unicode clause above ie if (name_len > buffersize-header) free buffer exit; BB */ strncpy(pSMB->FileName, searchName, name_len); - pSMB->FileName[name_len] = dirsep; - pSMB->FileName[name_len+1] = '*'; - pSMB->FileName[name_len+2] = 0; - name_len += 3; + if (dirsep) { + pSMB->FileName[name_len] = dirsep; + pSMB->FileName[name_len+1] = '*'; + pSMB->FileName[name_len+2] = 0; + name_len += 3; + } } params = 12 + name_len /* includes null */ ; + ffattrs = ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM; + if (dirsep) + ffattrs |= ATTR_DIRECTORY; pSMB->TotalDataCount = 0; /* no EAs */ pSMB->MaxParameterCount = cpu_to_le16(10); pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize & 0xFFFFFF00); @@ -4315,9 +4323,7 @@ findFirstRetry: pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */ pSMB->Reserved3 = 0; pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST); - pSMB->SearchAttributes = - cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | - ATTR_DIRECTORY); + pSMB->SearchAttributes = cpu_to_le16(ffattrs); pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO)); pSMB->SearchFlags = cpu_to_le16(search_flags); pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8e8bb49..a0ed97d 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -600,17 +600,40 @@ cgfi_exit: return rc; } +static void +fidinfo2fainfo(SEARCH_ID_FULL_DIR_INFO *fidinfo, FILE_ALL_INFO *fainfo) +{ + memcpy(&fainfo->CreationTime, &fidinfo->CreationTime, sizeof(__le64)); + memcpy(&fainfo->LastAccessTime, &fidinfo->LastAccessTime, + sizeof(__le64)); + memcpy(&fainfo->LastWriteTime, &fidinfo->LastWriteTime, + sizeof(__le64)); + memcpy(&fainfo->ChangeTime, &fidinfo->ChangeTime, + sizeof(__le64)); + memcpy(&fainfo->EndOfFile, &fidinfo->EndOfFile, + sizeof(__le64)); + memcpy(&fainfo->AllocationSize, &fidinfo->AllocationSize, + sizeof(__le64)); + memcpy(&fainfo->Attributes, &fidinfo->ExtFileAttributes, + sizeof(__le32)); + + return; +} + int cifs_get_inode_info(struct inode **pinode, const unsigned char *full_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid, const __u16 *pfid) { - int rc = 0, tmprc; + __u16 fid, srchflgs; + int rc = 0, rc2 = -EINVAL, tmprc; struct cifs_tcon *pTcon; struct tcon_link *tlink; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); char *buf = NULL; bool adjustTZ = false; struct cifs_fattr fattr; + struct cifs_search_info *psrch_inf = NULL; + SEARCH_ID_FULL_DIR_INFO *ffdata = NULL; tlink = cifs_sb_tlink(cifs_sb); if (IS_ERR(tlink)) @@ -640,6 +663,38 @@ int cifs_get_inode_info(struct inode **pinode, 0 /* not legacy */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + + /* + * This findfirst call is meant for a lookup operation + * that would otherwise fail since query path info has no + * means to indicate backup intent. + */ + if (rc == -EACCES && *pinode == NULL && backup_cred(cifs_sb)) { + psrch_inf = kzalloc(sizeof(struct cifs_search_info), + GFP_KERNEL); + if (psrch_inf == NULL) { + rc = -ENOMEM; + goto cgii_exit; + } + psrch_inf->endOfSearch = false; + psrch_inf->info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; + + srchflgs = CIFS_SEARCH_CLOSE_ALWAYS | + CIFS_SEARCH_CLOSE_AT_END | + CIFS_SEARCH_BACKUP_SEARCH; + + rc2 = CIFSFindFirst(xid, pTcon, full_path, + cifs_sb->local_nls, &fid, srchflgs, psrch_inf, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR, 0); + if (!rc2) { + ffdata = (SEARCH_ID_FULL_DIR_INFO *) + psrch_inf->srch_entries_start; + fidinfo2fainfo(ffdata, pfindData); + } + rc = rc2; + } + /* BB optimize code so we do not make the above call when server claims no NT SMB support and the above call failed at least once - set flag in tcon or mount */ @@ -683,7 +738,11 @@ int cifs_get_inode_info(struct inode **pinode, if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { int rc1 = 0; - rc1 = CIFSGetSrvInodeNumber(xid, pTcon, + if (!rc2) + fattr.cf_uniqueid = + le64_to_cpu(ffdata->UniqueId); + else + rc1 = CIFSGetSrvInodeNumber(xid, pTcon, full_path, &fattr.cf_uniqueid, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -741,6 +800,10 @@ int cifs_get_inode_info(struct inode **pinode, } cgii_exit: + if (!rc2) { + cifs_buf_release(psrch_inf->ntwrk_buf_start); + kfree(psrch_inf); + } kfree(buf); cifs_put_tlink(tlink); return rc;