@@ -255,7 +255,7 @@ static void cifs_begin_writeback(struct netfs_io_request *wreq)
255255 struct cifs_io_request * req = container_of (wreq , struct cifs_io_request , rreq );
256256 int ret ;
257257
258- ret = cifs_get_writable_file (CIFS_I (wreq -> inode ), FIND_WR_ANY , & req -> cfile );
258+ ret = cifs_get_writable_file (CIFS_I (wreq -> inode ), FIND_ANY , & req -> cfile );
259259 if (ret ) {
260260 cifs_dbg (VFS , "No writable handle in writepages ret=%d\n" , ret );
261261 return ;
@@ -956,7 +956,7 @@ int cifs_file_flush(const unsigned int xid, struct inode *inode,
956956 return tcon -> ses -> server -> ops -> flush (xid , tcon ,
957957 & cfile -> fid );
958958 }
959- rc = cifs_get_writable_file (CIFS_I (inode ), FIND_WR_ANY , & cfile );
959+ rc = cifs_get_writable_file (CIFS_I (inode ), FIND_ANY , & cfile );
960960 if (!rc ) {
961961 tcon = tlink_tcon (cfile -> tlink );
962962 rc = tcon -> ses -> server -> ops -> flush (xid , tcon , & cfile -> fid );
@@ -981,7 +981,7 @@ static int cifs_do_truncate(const unsigned int xid, struct dentry *dentry)
981981 return - ERESTARTSYS ;
982982 mapping_set_error (inode -> i_mapping , rc );
983983
984- cfile = find_writable_file (cinode , FIND_WR_FSUID_ONLY );
984+ cfile = find_writable_file (cinode , FIND_FSUID_ONLY );
985985 rc = cifs_file_flush (xid , inode , cfile );
986986 if (!rc ) {
987987 if (cfile ) {
@@ -1061,32 +1061,29 @@ int cifs_open(struct inode *inode, struct file *file)
10611061
10621062 /* Get the cached handle as SMB2 close is deferred */
10631063 if (OPEN_FMODE (file -> f_flags ) & FMODE_WRITE ) {
1064- rc = cifs_get_writable_path (tcon , full_path ,
1065- FIND_WR_FSUID_ONLY |
1066- FIND_WR_NO_PENDING_DELETE ,
1067- & cfile );
1064+ rc = __cifs_get_writable_file (CIFS_I (inode ),
1065+ FIND_FSUID_ONLY |
1066+ FIND_NO_PENDING_DELETE |
1067+ FIND_OPEN_FLAGS ,
1068+ file -> f_flags , & cfile );
10681069 } else {
1069- rc = cifs_get_readable_path (tcon , full_path , & cfile );
1070+ cfile = __find_readable_file (CIFS_I (inode ),
1071+ FIND_NO_PENDING_DELETE |
1072+ FIND_OPEN_FLAGS ,
1073+ file -> f_flags );
1074+ rc = cfile ? 0 : - ENOENT ;
10701075 }
10711076 if (rc == 0 ) {
1072- unsigned int oflags = file -> f_flags & ~(O_CREAT |O_EXCL |O_TRUNC );
1073- unsigned int cflags = cfile -> f_flags & ~(O_CREAT |O_EXCL |O_TRUNC );
1074-
1075- if (cifs_convert_flags (oflags , 0 ) == cifs_convert_flags (cflags , 0 ) &&
1076- (oflags & (O_SYNC |O_DIRECT )) == (cflags & (O_SYNC |O_DIRECT ))) {
1077- file -> private_data = cfile ;
1078- spin_lock (& CIFS_I (inode )-> deferred_lock );
1079- cifs_del_deferred_close (cfile );
1080- spin_unlock (& CIFS_I (inode )-> deferred_lock );
1081- goto use_cache ;
1082- }
1083- _cifsFileInfo_put (cfile , true, false);
1084- } else {
1085- /* hard link on the defeered close file */
1086- rc = cifs_get_hardlink_path (tcon , inode , file );
1087- if (rc )
1088- cifs_close_deferred_file (CIFS_I (inode ));
1089- }
1077+ file -> private_data = cfile ;
1078+ spin_lock (& CIFS_I (inode )-> deferred_lock );
1079+ cifs_del_deferred_close (cfile );
1080+ spin_unlock (& CIFS_I (inode )-> deferred_lock );
1081+ goto use_cache ;
1082+ }
1083+ /* hard link on the deferred close file */
1084+ rc = cifs_get_hardlink_path (tcon , inode , file );
1085+ if (rc )
1086+ cifs_close_deferred_file (CIFS_I (inode ));
10901087
10911088 if (server -> oplocks )
10921089 oplock = REQ_OPLOCK ;
@@ -2512,10 +2509,33 @@ void cifs_write_subrequest_terminated(struct cifs_io_subrequest *wdata, ssize_t
25122509 netfs_write_subrequest_terminated (& wdata -> subreq , result );
25132510}
25142511
2515- struct cifsFileInfo * find_readable_file (struct cifsInodeInfo * cifs_inode ,
2516- bool fsuid_only )
2512+ static bool open_flags_match (struct cifsInodeInfo * cinode ,
2513+ unsigned int oflags , unsigned int cflags )
2514+ {
2515+ struct inode * inode = & cinode -> netfs .inode ;
2516+ int crw = 0 , orw = 0 ;
2517+
2518+ oflags &= ~(O_CREAT | O_EXCL | O_TRUNC );
2519+ cflags &= ~(O_CREAT | O_EXCL | O_TRUNC );
2520+
2521+ if (cifs_fscache_enabled (inode )) {
2522+ if (OPEN_FMODE (cflags ) & FMODE_WRITE )
2523+ crw = 1 ;
2524+ if (OPEN_FMODE (oflags ) & FMODE_WRITE )
2525+ orw = 1 ;
2526+ }
2527+ if (cifs_convert_flags (oflags , orw ) != cifs_convert_flags (cflags , crw ))
2528+ return false;
2529+
2530+ return (oflags & (O_SYNC | O_DIRECT )) == (cflags & (O_SYNC | O_DIRECT ));
2531+ }
2532+
2533+ struct cifsFileInfo * __find_readable_file (struct cifsInodeInfo * cifs_inode ,
2534+ unsigned int find_flags ,
2535+ unsigned int open_flags )
25172536{
25182537 struct cifs_sb_info * cifs_sb = CIFS_SB (cifs_inode );
2538+ bool fsuid_only = find_flags & FIND_FSUID_ONLY ;
25192539 struct cifsFileInfo * open_file = NULL ;
25202540
25212541 /* only filter by fsuid on multiuser mounts */
@@ -2529,6 +2549,13 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
25292549 list_for_each_entry (open_file , & cifs_inode -> openFileList , flist ) {
25302550 if (fsuid_only && !uid_eq (open_file -> uid , current_fsuid ()))
25312551 continue ;
2552+ if ((find_flags & FIND_NO_PENDING_DELETE ) &&
2553+ open_file -> status_file_deleted )
2554+ continue ;
2555+ if ((find_flags & FIND_OPEN_FLAGS ) &&
2556+ !open_flags_match (cifs_inode , open_flags ,
2557+ open_file -> f_flags ))
2558+ continue ;
25322559 if (OPEN_FMODE (open_file -> f_flags ) & FMODE_READ ) {
25332560 if ((!open_file -> invalidHandle )) {
25342561 /* found a good file */
@@ -2547,17 +2574,17 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
25472574}
25482575
25492576/* Return -EBADF if no handle is found and general rc otherwise */
2550- int
2551- cifs_get_writable_file ( struct cifsInodeInfo * cifs_inode , int flags ,
2552- struct cifsFileInfo * * ret_file )
2577+ int __cifs_get_writable_file ( struct cifsInodeInfo * cifs_inode ,
2578+ unsigned int find_flags , unsigned int open_flags ,
2579+ struct cifsFileInfo * * ret_file )
25532580{
25542581 struct cifsFileInfo * open_file , * inv_file = NULL ;
25552582 struct cifs_sb_info * cifs_sb ;
25562583 bool any_available = false;
25572584 int rc = - EBADF ;
25582585 unsigned int refind = 0 ;
2559- bool fsuid_only = flags & FIND_WR_FSUID_ONLY ;
2560- bool with_delete = flags & FIND_WR_WITH_DELETE ;
2586+ bool fsuid_only = find_flags & FIND_FSUID_ONLY ;
2587+ bool with_delete = find_flags & FIND_WITH_DELETE ;
25612588 * ret_file = NULL ;
25622589
25632590 /*
@@ -2591,9 +2618,13 @@ cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, int flags,
25912618 continue ;
25922619 if (with_delete && !(open_file -> fid .access & DELETE ))
25932620 continue ;
2594- if ((flags & FIND_WR_NO_PENDING_DELETE ) &&
2621+ if ((find_flags & FIND_NO_PENDING_DELETE ) &&
25952622 open_file -> status_file_deleted )
25962623 continue ;
2624+ if ((find_flags & FIND_OPEN_FLAGS ) &&
2625+ !open_flags_match (cifs_inode , open_flags ,
2626+ open_file -> f_flags ))
2627+ continue ;
25972628 if (OPEN_FMODE (open_file -> f_flags ) & FMODE_WRITE ) {
25982629 if (!open_file -> invalidHandle ) {
25992630 /* found a good writable file */
@@ -2710,17 +2741,7 @@ cifs_get_readable_path(struct cifs_tcon *tcon, const char *name,
27102741 cinode = CIFS_I (d_inode (cfile -> dentry ));
27112742 spin_unlock (& tcon -> open_file_lock );
27122743 free_dentry_path (page );
2713- * ret_file = find_readable_file (cinode , 0 );
2714- if (* ret_file ) {
2715- spin_lock (& cinode -> open_file_lock );
2716- if ((* ret_file )-> status_file_deleted ) {
2717- spin_unlock (& cinode -> open_file_lock );
2718- cifsFileInfo_put (* ret_file );
2719- * ret_file = NULL ;
2720- } else {
2721- spin_unlock (& cinode -> open_file_lock );
2722- }
2723- }
2744+ * ret_file = find_readable_file (cinode , FIND_ANY );
27242745 return * ret_file ? 0 : - ENOENT ;
27252746 }
27262747
@@ -2792,7 +2813,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
27922813 }
27932814
27942815 if ((OPEN_FMODE (smbfile -> f_flags ) & FMODE_WRITE ) == 0 ) {
2795- smbfile = find_writable_file (CIFS_I (inode ), FIND_WR_ANY );
2816+ smbfile = find_writable_file (CIFS_I (inode ), FIND_ANY );
27962817 if (smbfile ) {
27972818 rc = server -> ops -> flush (xid , tcon , & smbfile -> fid );
27982819 cifsFileInfo_put (smbfile );
0 commit comments