Re: Strange hardlink behavior with CIFS

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

 



On Fri, 29 Oct 2010 16:21:41 +0530
Suresh Jayaraman <sjayaraman@xxxxxxx> wrote:

> On 10/28/2010 05:16 PM, Jeff Layton wrote:
> > On Thu, 28 Oct 2010 16:38:28 +0530
> > Suresh Jayaraman <sjayaraman@xxxxxxx> wrote:
> > 
> >> On 10/28/2010 02:02 AM, Jeff Layton wrote:
> >>> On Wed, 27 Oct 2010 12:31:26 -0500
> >>> Matt Mackall <mpm@xxxxxxxxxxx> wrote:
> >>>
> >>>> On Tue, 2010-10-19 at 15:13 +0530, Suresh Jayaraman wrote:
> >>>>> On 10/19/2010 12:34 AM, Matt Mackall wrote:
> >>>>>> With Linux 2.6.32-35 and either Windows or Samba in nounix mode,
> >>>>>> hardlink counts can mysteriously disappear:
> >>>>>>
> >>>>>> - create hardlink pair foo,bar
> >>>>>> - stat foo -> nlink = 2
> >>>>>> - open foo
> >>>>>> - stat foo -> nlink = 1
> >>>>>> - close
> >>>>>> - wait or sync
> >>>>>> - ls -l -> nlink = 2
> >>>>>>
> 
> > 
> > I think we ought to not have CIFSSMBOpen try to fake up values since
> > it's clearly incorrect. The easiest way is just to get rid of the
> > places that try to do that (like this one).
> > 
> > If we feel that it's important to try and use the values that are
> > returned from this call (and others that fake up a QPathInfo response
> > like this), then they ought to changed so that they put the info into a
> > cifs_fattr struct and then update the inode values from that.
> > 
> > To do that however, you'll need to fix cifs_fattr_to_inode to only
> > update the values that have been set in the cifs_fattr so that you're
> > not faking up other values. That may mean adding a "valid" field of
> > some sort and setting flags that show which fields should be copied to
> > the inode.
> > 
> 
> Great idea, Thanks.
> 
> Looks like we could overload fattr->cf_flags. Something like this?
> (Only compile tested as I screwed up my VM setup)
> 
> 
>  fs/cifs/cifsglob.h |    1 +
>  fs/cifs/cifssmb.c  |    2 +-
>  fs/cifs/inode.c    |    8 ++++++--
>  3 files changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index f259e4d..bdb508f 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -558,6 +558,7 @@ struct dfs_info3_param {
>  #define CIFS_FATTR_DELETE_PENDING	0x2
>  #define CIFS_FATTR_NEED_REVAL		0x4
>  #define CIFS_FATTR_INO_COLLISION	0x8
> +#define CIFS_FATTR_NLINK_NOT_SET	0x10	/* number of hardlinks unknown */
>  
>  struct cifs_fattr {
>  	u32		cf_flags;
> diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
> index 2f2632b..6a5455f 100644
> --- a/fs/cifs/cifssmb.c
> +++ b/fs/cifs/cifssmb.c
> @@ -1326,7 +1326,7 @@ openRetry:
>  			/* the file_info buf is endian converted by caller */
>  			pfile_info->AllocationSize = pSMBr->AllocationSize;
>  			pfile_info->EndOfFile = pSMBr->EndOfFile;
> -			pfile_info->NumberOfLinks = cpu_to_le32(1);
> +			pfile_info->NumberOfLinks = 0; /* not known */
>  			pfile_info->DeletePending = 0;
>  		}
>  	}
> diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
> index 39869c3..7ab9a62 100644
> --- a/fs/cifs/inode.c
> +++ b/fs/cifs/inode.c
> @@ -128,7 +128,8 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
>  	inode->i_mtime = fattr->cf_mtime;
>  	inode->i_ctime = fattr->cf_ctime;
>  	inode->i_rdev = fattr->cf_rdev;
> -	inode->i_nlink = fattr->cf_nlink;
> +	if (!(fattr->cf_flags & CIFS_FATTR_NLINK_NOT_SET))
> +		inode->i_nlink = fattr->cf_nlink;
>  	inode->i_uid = fattr->cf_uid;
>  	inode->i_gid = fattr->cf_gid;
>  
> @@ -531,7 +532,10 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
>  			fattr->cf_mode &= ~(S_IWUGO);
>  	}
>  
> -	fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
> +	if (info->NumberOfLinks)
> +		fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
> +	else
> +		fattr->cf_flags |= CIFS_FATTR_NLINK_NOT_SET;
>  
>  	fattr->cf_uid = cifs_sb->mnt_uid;
>  	fattr->cf_gid = cifs_sb->mnt_gid;

No, I don't think that's going to do it...

With that you're basically just saying "when the server reports zero
nlinks, just ignore it". That not really correct, at least not with
samba. I'm not sure how that would work with windows semantics, but
it's probably best not to do this.

Suppose I hold a file open and something unlinks the dentry. Then I
do a QFileInfo against the open filehandle. The file will still exist,
but it'll have 0 nlinks. This approach will also make the metadata
wrong.

What you really want to do is fix CIFSSMBOpen to take a cifs_fattr
pointer instead of a buffer, populate that with the values from the open
response, and set flags to make cifs_fattr_to_inode ignore everything
else.

You'll then want to make cifs_open just call cifs_fattr_to_inode
directly instead of calling cifs_get_inode_info. You can probably also
eliminate cifs_open_inode_helper in the process, though you'll need to
look at the logic carefully and may need to move some of it into
cifs_open.

-- 
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