@@ -3307,53 +3307,56 @@ get_smb2_acl(struct cifs_sb_info *cifs_sb,
33073307 return pntsd ;
33083308}
33093309
3310+ static long smb3_zero_data (struct file * file , struct cifs_tcon * tcon ,
3311+ loff_t offset , loff_t len , unsigned int xid )
3312+ {
3313+ struct cifsFileInfo * cfile = file -> private_data ;
3314+ struct file_zero_data_information fsctl_buf ;
3315+
3316+ cifs_dbg (FYI , "Offset %lld len %lld\n" , offset , len );
3317+
3318+ fsctl_buf .FileOffset = cpu_to_le64 (offset );
3319+ fsctl_buf .BeyondFinalZero = cpu_to_le64 (offset + len );
3320+
3321+ return SMB2_ioctl (xid , tcon , cfile -> fid .persistent_fid ,
3322+ cfile -> fid .volatile_fid , FSCTL_SET_ZERO_DATA ,
3323+ (char * )& fsctl_buf ,
3324+ sizeof (struct file_zero_data_information ),
3325+ 0 , NULL , NULL );
3326+ }
3327+
33103328static long smb3_zero_range (struct file * file , struct cifs_tcon * tcon ,
33113329 loff_t offset , loff_t len , bool keep_size )
33123330{
33133331 struct cifs_ses * ses = tcon -> ses ;
3314- struct inode * inode ;
3315- struct cifsInodeInfo * cifsi ;
3332+ struct inode * inode = file_inode ( file ) ;
3333+ struct cifsInodeInfo * cifsi = CIFS_I ( inode ) ;
33163334 struct cifsFileInfo * cfile = file -> private_data ;
3317- struct file_zero_data_information fsctl_buf ;
33183335 long rc ;
33193336 unsigned int xid ;
33203337 __le64 eof ;
33213338
33223339 xid = get_xid ();
33233340
3324- inode = d_inode (cfile -> dentry );
3325- cifsi = CIFS_I (inode );
3326-
33273341 trace_smb3_zero_enter (xid , cfile -> fid .persistent_fid , tcon -> tid ,
33283342 ses -> Suid , offset , len );
33293343
3344+ inode_lock (inode );
3345+ filemap_invalidate_lock (inode -> i_mapping );
3346+
33303347 /*
33313348 * We zero the range through ioctl, so we need remove the page caches
33323349 * first, otherwise the data may be inconsistent with the server.
33333350 */
33343351 truncate_pagecache_range (inode , offset , offset + len - 1 );
33353352
33363353 /* if file not oplocked can't be sure whether asking to extend size */
3337- if (!CIFS_CACHE_READ (cifsi ))
3338- if (keep_size == false) {
3339- rc = - EOPNOTSUPP ;
3340- trace_smb3_zero_err (xid , cfile -> fid .persistent_fid ,
3341- tcon -> tid , ses -> Suid , offset , len , rc );
3342- free_xid (xid );
3343- return rc ;
3344- }
3345-
3346- cifs_dbg (FYI , "Offset %lld len %lld\n" , offset , len );
3347-
3348- fsctl_buf .FileOffset = cpu_to_le64 (offset );
3349- fsctl_buf .BeyondFinalZero = cpu_to_le64 (offset + len );
3354+ rc = - EOPNOTSUPP ;
3355+ if (keep_size == false && !CIFS_CACHE_READ (cifsi ))
3356+ goto zero_range_exit ;
33503357
3351- rc = SMB2_ioctl (xid , tcon , cfile -> fid .persistent_fid ,
3352- cfile -> fid .volatile_fid , FSCTL_SET_ZERO_DATA ,
3353- (char * )& fsctl_buf ,
3354- sizeof (struct file_zero_data_information ),
3355- 0 , NULL , NULL );
3356- if (rc )
3358+ rc = smb3_zero_data (file , tcon , offset , len , xid );
3359+ if (rc < 0 )
33573360 goto zero_range_exit ;
33583361
33593362 /*
@@ -3366,6 +3369,8 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
33663369 }
33673370
33683371 zero_range_exit :
3372+ filemap_invalidate_unlock (inode -> i_mapping );
3373+ inode_unlock (inode );
33693374 free_xid (xid );
33703375 if (rc )
33713376 trace_smb3_zero_err (xid , cfile -> fid .persistent_fid , tcon -> tid ,
@@ -3379,7 +3384,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
33793384static long smb3_punch_hole (struct file * file , struct cifs_tcon * tcon ,
33803385 loff_t offset , loff_t len )
33813386{
3382- struct inode * inode ;
3387+ struct inode * inode = file_inode ( file ) ;
33833388 struct cifsFileInfo * cfile = file -> private_data ;
33843389 struct file_zero_data_information fsctl_buf ;
33853390 long rc ;
@@ -3388,14 +3393,12 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
33883393
33893394 xid = get_xid ();
33903395
3391- inode = d_inode (cfile -> dentry );
3392-
3396+ inode_lock (inode );
33933397 /* Need to make file sparse, if not already, before freeing range. */
33943398 /* Consider adding equivalent for compressed since it could also work */
33953399 if (!smb2_set_sparse (xid , tcon , cfile , inode , set_sparse )) {
33963400 rc = - EOPNOTSUPP ;
3397- free_xid (xid );
3398- return rc ;
3401+ goto out ;
33993402 }
34003403
34013404 filemap_invalidate_lock (inode -> i_mapping );
@@ -3415,8 +3418,10 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
34153418 (char * )& fsctl_buf ,
34163419 sizeof (struct file_zero_data_information ),
34173420 CIFSMaxBufSize , NULL , NULL );
3418- free_xid (xid );
34193421 filemap_invalidate_unlock (inode -> i_mapping );
3422+ out :
3423+ inode_unlock (inode );
3424+ free_xid (xid );
34203425 return rc ;
34213426}
34223427
0 commit comments