Re: [PATCH] cifs: Allow mounts for paths for restricted intermediate paths

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

 



On Tue, Nov 19, 2013 at 2:59 PM, Jeff Layton <jlayton@xxxxxxxxxx> wrote:
> On Tue, 19 Nov 2013 10:33:33 -0600
> shirishpargaonkar@xxxxxxxxx wrote:
>
>> From: Shirish Pargaonkar <shirishpargaonkar@xxxxxxxxx>
>>
>>
>> Allow cifs mounts for a prefixpath with intermediate paths without access,
>> so as to continue with the shared superblock model.
>>
>> For the intermediate path entries that do not allow access, create "placeholder"
>> inodes and instantiate dentries with those inodes.
>> If and when such a path entry becomes accessible it is filled with correct
>> info.
>>
>
> I'm unclear on this last bit...
>
> How exactly do they end up being filled with the correct info once that
> happens?

I was thinking when the access permissions for this directory change
on the server.

For example,  if we had two mounts with shared superblocks
/mnt_m/a/b
/mnt_n
where a was inaccessible.  If the permissions change on a such that
it becomes accessible, stat /mnt_n/a will fetch correct info.

>
>> Reference: Samba bugzilla 6950
>>
>> Signed-off-by: Shirish Pargaonkar <spargaonkar@xxxxxxxx>
>>
>> ---
>>  fs/cifs/cifsfs.c    | 17 +++++++++++++++--
>>  fs/cifs/cifsproto.h |  3 +++
>>  fs/cifs/inode.c     | 16 ++++++++++++++++
>>  3 files changed, 34 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
>> index 849f613..bce185c 100644
>> --- a/fs/cifs/cifsfs.c
>> +++ b/fs/cifs/cifsfs.c
>> @@ -584,6 +584,9 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
>>       char *full_path = NULL;
>>       char *s, *p;
>>       char sep;
>> +     struct inode *dir, *phinode;
>> +     struct dentry *child;
>> +     struct cifs_fattr phfattr;
>>
>>       full_path = cifs_build_path_to_root(vol, cifs_sb,
>>                                           cifs_sb_master_tcon(cifs_sb));
>> @@ -592,13 +595,13 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
>>
>>       cifs_dbg(FYI, "Get root dentry for %s\n", full_path);
>>
>> +     fill_phfattr(&phfattr, sb);
>
> Hmmm...so this function sets up a cifs_fattr struct, including the
> cf_uniqueid...which won't be very unique when you reuse that struct
> several times in the do...while loop below. Don't you need to call it
> again after you use it once?
>

That was silly.   Will fix that.

>>       sep = CIFS_DIR_SEP(cifs_sb);
>>       dentry = dget(sb->s_root);
>>       p = s = full_path;
>>
>>       do {
>> -             struct inode *dir = dentry->d_inode;
>> -             struct dentry *child;
>> +             dir = dentry->d_inode;
>>
>>               if (!dir) {
>>                       dput(dentry);
>> @@ -626,6 +629,16 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb)
>>               mutex_unlock(&dir->i_mutex);
>>               dput(dentry);
>>               dentry = child;
>> +             if (!IS_ERR(dentry)) {
>> +                     if (*s) {
>> +                             /* EACCESS on an intermediate dir */
>> +                             if (!dentry->d_inode) {
>> +                                     phinode = cifs_iget(sb, &phfattr);
>> +                                     if (phinode)
>> +                                             d_instantiate(dentry, phinode);
>> +                             }
>> +                     }
>> +             }
>
> This doesn't make any sense to me.
>
> The do...while loop here is basically doing lookups and instantiating
> dentries and inodes down from the root of the mount to the root of the
> share. The lookup_one_len call is what does the single-level lookup in
> that directory.
>
> Why are you adding special handling when "dentry" is not an error?
> Would it not make more sense to do so when lookup_one_len does return
> an error?

If server returns ENOENT, lookup_one_len will return with a negative
dentry.  This is the case I was handling.  Need to access EACCESS.
Not sure why/when server returns ENOENT (object not found) even when
the (directory) entry exists.

>
>>       } while (!IS_ERR(dentry));
>>       kfree(full_path);
>>       return dentry;
>> diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
>> index aa33976..9a84e5c 100644
>> --- a/fs/cifs/cifsproto.h
>> +++ b/fs/cifs/cifsproto.h
>> @@ -498,4 +498,7 @@ void cifs_writedata_release(struct kref *refcount);
>>  int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
>>                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
>>                       unsigned int xid);
>> +
>> +extern void fill_phfattr(struct cifs_fattr *, struct super_block *);
>> +
>>  #endif                       /* _CIFSPROTO_H */
>> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
>> index 36f9ebb..4f5a09a 100644
>> --- a/fs/cifs/inode.c
>> +++ b/fs/cifs/inode.c
>> @@ -322,6 +322,22 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
>>       fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
>>  }
>>
>> +void
>> +fill_phfattr(struct cifs_fattr *cf, struct super_block *sb)
>> +{
>> +     struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
>> +
>> +     memset(cf, 0, sizeof(*cf));
>> +     cf->cf_uniqueid = iunique(sb, ROOT_I);
>
>
> Also, iunique is only guaranteed to return a number that hasn't yet
> been used. So suppose we're going to instantiate one of these bogus
> inodes. We give it the uniqueid of '3'. Then later, once the mount is
> done we find another (legitimate) inode on the server and it also has a
> uniqueid of '3'. Now you have a collision. Worse yet, if it's a
> directory now it looks like we have a hardlinked directory...
>
> Once you start using iunique, you can't really go back to using server
> inode numbers since you can't guarantee that there won't be collisions.
>
> One possibility to deal with that would be to tag these entries as
> bogus and ensure that cifs_iget will never match them. Another
> possibility might be just to never hash these inodes, but I'm not clear
> on how kosher that is from a vfs standpoint.

Looking into this.


>
>> +     cf->cf_nlink = 1;
>> +     cf->cf_atime = CURRENT_TIME;
>> +     cf->cf_ctime = CURRENT_TIME;
>> +     cf->cf_mtime = CURRENT_TIME;
>> +     cf->cf_mode = S_IFDIR | S_IXUGO | S_IRWXU;
>> +     cf->cf_uid = cifs_sb->mnt_uid;
>> +     cf->cf_gid = cifs_sb->mnt_gid;
>> +}
>> +
>
>
>>  static int
>>  cifs_get_file_info_unix(struct file *filp)
>>  {
>
>
> I think the thing to do is to step back and describe (in English) how
> you envision this working. Then once that's done, we can start
> discussing what the code should look like...
>
> --
> Jeff Layton <jlayton@xxxxxxxxxx>
--
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