Re: [PATCH v2] cifs: obtain file access during backup intent lookup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 2, 2012 at 9:37 AM, Jeff Layton <jlayton@xxxxxxxxx> wrote:
> On Thu, 2 Aug 2012 01:07:45 -0500
> Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx> wrote:
>
>> On Mon, Jul 30, 2012 at 6:00 AM, Jeff Layton <jlayton@xxxxxxxxx> wrote:
>> > On Wed, 25 Jul 2012 17:45:04 -0500
>> > shirishpargaonkar@xxxxxxxxx wrote:
>> >
>> >> From: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx>
>> >>
>> >> 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 <shirishpargaonkar@xxxxxxxxx>
>> >> Reported-by: Tushar Gosavi <tugosavi@xxxxxxxxxx>
>> >> ---
>> >>  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) {
>> >
>> > This seems like a strange use of the "dirsep" parm. So if you are using
>> > this to do a single lookup, then you pass in 0 for dirsep. I guess
>> > it'll work, but it's not exactly self-documenting.
>>
>> How do I otherwise figure out / distinguish that the findfirst  operation
>> is for a file/leaf and not a directory.
>>
>> >
>> >> +                     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;
>> >         ^^^
>> > I don't understand this. You're only setting ATTR_DIRECTORY for a readdir()? Why?
>>
>> Because what I see is, trans2/qpathinfo does not fail on directory, only
>> does so for a file.  So if dirsep is 0, we are looking for a file and dirsep
>> is not 0, findfirst is for a directory.
>>
>
> I'm not sure I understand that logic. In fact, I'm not sure I
> understand the semantics behind the use of ATTR_DIRECTORY here at all.
> What if you're doing a lookup on directory? Does that mean that it will
> now be excluded?
>
> MS-CIFS says:
>
> "SearchAttributes (2 bytes): File attributes to apply as a constraint to
> the file search. Exclusive search attributes (see section 2.2.1.2.4)
> can also be set."
>
> ...which makes it sound like you're constraining the search only to
> directories when dirsep is set.
>
> If it's necessary to do the above, then a comment explaining why would
> be best.

I will spend some time on using dirsep and making use of dirsep
more (self) explanatory.

What I see is, findfirst does not need to be employed because
access is not denied when query'ing attributes of a directory
i.e. trans2/query path info/infolevel always succeeds in case of a
directory.

So when we are (for now) using findfirst as a substitute when
query path info is denied access on a file, ATTR_DIRECTORY
is never needed and until this point, I was using dirsep to distinguish
that in common findfirst code.

>
> Eventually, I think we should consider using this for all lookups
> instead of QPathInfo if we can. In the event that you are using server
> inode numbers, this could cut down round trips to the server by half.
> Currently we have to do a separate CIFSGetSrvInodeNumber call on every
> lookup. It would be nice if we could turn that into a single call.
>
>> >
>> >>       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;
>> >> +}
>> >> +
>> >
>> >
>> > Yuck. So you're going to take the SEARCH_ID_FULL_DIR_INFO and convert
>> > that to FILE_ALL_INFO, just so it can then be converted to a
>> > cifs_fattr? Why not shortcut this step, and turn it into a fattr
>> > directly. I think we already have some routines to do that.
>>
>> I will look into code to use any existing one, if not write a new similar one
>> that converts search_id_full_dir_info to fattr.
>>
>
> There are such functions in the readdir code, but you'll probably have
> to handle the cf_uniqueid separately.
>
>> >
>> >>  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);
>> >
>> > Won't ffdata only be non-NULL if you fall into the new code block
>> > above? That looks like it could oops.
>>
>> rc2 is set as -EINVAL.  If we do not fall into the new code, rc2 is not 0
>> i.e. !rc2 is false.  If we fall into new code and findfirst call is successful,
>> rc2 is 0 and !rc2 is true but if findfirst call fails, rc2 is not 0 and
>> so !rc2 is false.  So I do not think we will oops because ffdata is NULL.
>>
>
> Ick ok. That's very subtle. It would be nice to clean up this function
> some so that there are not so many subtleties. It's probably time to
> break it up into multiple functions.
>
>> >
>> >> +                     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;
>> >
>> >
>
>
> --
> Jeff Layton <jlayton@xxxxxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux