@@ -55,6 +55,23 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
55
55
}
56
56
#endif /* DEBUG2 */
57
57
58
+ /*
59
+ * Match a reparse point inode if reparse tag and ctime haven't changed.
60
+ *
61
+ * Windows Server updates ctime of reparse points when their data have changed.
62
+ * The server doesn't allow changing reparse tags from existing reparse points,
63
+ * though it's worth checking.
64
+ */
65
+ static inline bool reparse_inode_match (struct inode * inode ,
66
+ struct cifs_fattr * fattr )
67
+ {
68
+ struct timespec64 ctime = inode_get_ctime (inode );
69
+
70
+ return (CIFS_I (inode )-> cifsAttrs & ATTR_REPARSE ) &&
71
+ CIFS_I (inode )-> reparse_tag == fattr -> cf_cifstag &&
72
+ timespec64_equal (& ctime , & fattr -> cf_ctime );
73
+ }
74
+
58
75
/*
59
76
* Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
60
77
*
@@ -71,6 +88,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
71
88
struct super_block * sb = parent -> d_sb ;
72
89
struct cifs_sb_info * cifs_sb = CIFS_SB (sb );
73
90
DECLARE_WAIT_QUEUE_HEAD_ONSTACK (wq );
91
+ int rc ;
74
92
75
93
cifs_dbg (FYI , "%s: for %s\n" , __func__ , name -> name );
76
94
@@ -82,9 +100,11 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
82
100
* We'll end up doing an on the wire call either way and
83
101
* this spares us an invalidation.
84
102
*/
85
- if (fattr -> cf_flags & CIFS_FATTR_NEED_REVAL )
86
- return ;
87
103
retry :
104
+ if ((fattr -> cf_cifsattrs & ATTR_REPARSE ) ||
105
+ (fattr -> cf_flags & CIFS_FATTR_NEED_REVAL ))
106
+ return ;
107
+
88
108
dentry = d_alloc_parallel (parent , name , & wq );
89
109
}
90
110
if (IS_ERR (dentry ))
@@ -104,12 +124,34 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
104
124
if (!(cifs_sb -> mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM ))
105
125
fattr -> cf_uniqueid = CIFS_I (inode )-> uniqueid ;
106
126
107
- /* update inode in place
108
- * if both i_ino and i_mode didn't change */
109
- if (CIFS_I (inode )-> uniqueid == fattr -> cf_uniqueid &&
110
- cifs_fattr_to_inode (inode , fattr ) == 0 ) {
111
- dput (dentry );
112
- return ;
127
+ /*
128
+ * Update inode in place if both i_ino and i_mode didn't
129
+ * change.
130
+ */
131
+ if (CIFS_I (inode )-> uniqueid == fattr -> cf_uniqueid ) {
132
+ /*
133
+ * Query dir responses don't provide enough
134
+ * information about reparse points other than
135
+ * their reparse tags. Save an invalidation by
136
+ * not clobbering the existing mode, size and
137
+ * symlink target (if any) when reparse tag and
138
+ * ctime haven't changed.
139
+ */
140
+ rc = 0 ;
141
+ if (fattr -> cf_cifsattrs & ATTR_REPARSE ) {
142
+ if (likely (reparse_inode_match (inode , fattr ))) {
143
+ fattr -> cf_mode = inode -> i_mode ;
144
+ fattr -> cf_eof = CIFS_I (inode )-> server_eof ;
145
+ fattr -> cf_symlink_target = NULL ;
146
+ } else {
147
+ CIFS_I (inode )-> time = 0 ;
148
+ rc = - ESTALE ;
149
+ }
150
+ }
151
+ if (!rc && !cifs_fattr_to_inode (inode , fattr )) {
152
+ dput (dentry );
153
+ return ;
154
+ }
113
155
}
114
156
}
115
157
d_invalidate (dentry );
@@ -127,29 +169,6 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
127
169
dput (dentry );
128
170
}
129
171
130
- static bool reparse_file_needs_reval (const struct cifs_fattr * fattr )
131
- {
132
- if (!(fattr -> cf_cifsattrs & ATTR_REPARSE ))
133
- return false;
134
- /*
135
- * The DFS tags should be only intepreted by server side as per
136
- * MS-FSCC 2.1.2.1, but let's include them anyway.
137
- *
138
- * Besides, if cf_cifstag is unset (0), then we still need it to be
139
- * revalidated to know exactly what reparse point it is.
140
- */
141
- switch (fattr -> cf_cifstag ) {
142
- case IO_REPARSE_TAG_DFS :
143
- case IO_REPARSE_TAG_DFSR :
144
- case IO_REPARSE_TAG_SYMLINK :
145
- case IO_REPARSE_TAG_NFS :
146
- case IO_REPARSE_TAG_MOUNT_POINT :
147
- case 0 :
148
- return true;
149
- }
150
- return false;
151
- }
152
-
153
172
static void
154
173
cifs_fill_common_info (struct cifs_fattr * fattr , struct cifs_sb_info * cifs_sb )
155
174
{
@@ -181,14 +200,6 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
181
200
}
182
201
183
202
out_reparse :
184
- /*
185
- * We need to revalidate it further to make a decision about whether it
186
- * is a symbolic link, DFS referral or a reparse point with a direct
187
- * access like junctions, deduplicated files, NFS symlinks.
188
- */
189
- if (reparse_file_needs_reval (fattr ))
190
- fattr -> cf_flags |= CIFS_FATTR_NEED_REVAL ;
191
-
192
203
/* non-unix readdir doesn't provide nlink */
193
204
fattr -> cf_flags |= CIFS_FATTR_UNKNOWN_NLINK ;
194
205
@@ -269,9 +280,6 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
269
280
fattr -> cf_dtype = DT_REG ;
270
281
}
271
282
272
- if (reparse_file_needs_reval (fattr ))
273
- fattr -> cf_flags |= CIFS_FATTR_NEED_REVAL ;
274
-
275
283
sid_to_id (cifs_sb , & parsed .owner , fattr , SIDOWNER );
276
284
sid_to_id (cifs_sb , & parsed .group , fattr , SIDGROUP );
277
285
}
@@ -331,38 +339,6 @@ cifs_std_info_to_fattr(struct cifs_fattr *fattr, FIND_FILE_STANDARD_INFO *info,
331
339
cifs_fill_common_info (fattr , cifs_sb );
332
340
}
333
341
334
- /* BB eventually need to add the following helper function to
335
- resolve NT_STATUS_STOPPED_ON_SYMLINK return code when
336
- we try to do FindFirst on (NTFS) directory symlinks */
337
- /*
338
- int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
339
- unsigned int xid)
340
- {
341
- __u16 fid;
342
- int len;
343
- int oplock = 0;
344
- int rc;
345
- struct cifs_tcon *ptcon = cifs_sb_tcon(cifs_sb);
346
- char *tmpbuffer;
347
-
348
- rc = CIFSSMBOpen(xid, ptcon, full_path, FILE_OPEN, GENERIC_READ,
349
- OPEN_REPARSE_POINT, &fid, &oplock, NULL,
350
- cifs_sb->local_nls,
351
- cifs_remap(cifs_sb);
352
- if (!rc) {
353
- tmpbuffer = kmalloc(maxpath);
354
- rc = CIFSSMBQueryReparseLinkInfo(xid, ptcon, full_path,
355
- tmpbuffer,
356
- maxpath -1,
357
- fid,
358
- cifs_sb->local_nls);
359
- if (CIFSSMBClose(xid, ptcon, fid)) {
360
- cifs_dbg(FYI, "Error closing temporary reparsepoint open\n");
361
- }
362
- }
363
- }
364
- */
365
-
366
342
static int
367
343
_initiate_cifs_search (const unsigned int xid , struct file * file ,
368
344
const char * full_path )
@@ -431,13 +407,10 @@ _initiate_cifs_search(const unsigned int xid, struct file *file,
431
407
& cifsFile -> fid , search_flags ,
432
408
& cifsFile -> srch_inf );
433
409
434
- if (rc == 0 )
410
+ if (rc == 0 ) {
435
411
cifsFile -> invalidHandle = false;
436
- /* BB add following call to handle readdir on new NTFS symlink errors
437
- else if STATUS_STOPPED_ON_SYMLINK
438
- call get_symlink_reparse_path and retry with new path */
439
- else if ((rc == - EOPNOTSUPP ) &&
440
- (cifs_sb -> mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM )) {
412
+ } else if ((rc == - EOPNOTSUPP ) &&
413
+ (cifs_sb -> mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM )) {
441
414
cifs_sb -> mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM ;
442
415
goto ffirst_retry ;
443
416
}
0 commit comments