diff options
author | David Howells <dhowells@redhat.com> | 2019-06-20 13:12:16 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-06-20 13:12:16 -0400 |
commit | 051d25250b55c215a2254a0130d46fbd38bcbcc0 (patch) | |
tree | 0e53a2801fb6f964d85e663435041c01943cb878 | |
parent | fa59f52f5b1412c373813e24e7cbe5ab44518ed8 (diff) |
afs: Add some callback management tracepoints
Add a couple of tracepoints to track callback management:
(1) afs_cb_miss - Logs when we were unable to apply a callback, either due
to the inode being discarded or due to a competing thread applying a
callback first.
(2) afs_cb_break - Logs when we attempted to clear the noted callback
promise, either due to the server explicitly breaking the callback,
the callback promise lapsing or a local event obsoleting it.
Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r-- | fs/afs/callback.c | 16 | ||||
-rw-r--r-- | fs/afs/dir.c | 4 | ||||
-rw-r--r-- | fs/afs/inode.c | 17 | ||||
-rw-r--r-- | fs/afs/internal.h | 8 | ||||
-rw-r--r-- | include/trace/events/afs.h | 69 |
5 files changed, 97 insertions, 17 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 915010464572..d66cd0364243 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -212,7 +212,7 @@ void afs_init_callback_state(struct afs_server *server) | |||
212 | /* | 212 | /* |
213 | * actually break a callback | 213 | * actually break a callback |
214 | */ | 214 | */ |
215 | void __afs_break_callback(struct afs_vnode *vnode) | 215 | void __afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) |
216 | { | 216 | { |
217 | _enter(""); | 217 | _enter(""); |
218 | 218 | ||
@@ -223,13 +223,17 @@ void __afs_break_callback(struct afs_vnode *vnode) | |||
223 | 223 | ||
224 | if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) | 224 | if (vnode->lock_state == AFS_VNODE_LOCK_WAITING_FOR_CB) |
225 | afs_lock_may_be_available(vnode); | 225 | afs_lock_may_be_available(vnode); |
226 | |||
227 | trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, true); | ||
228 | } else { | ||
229 | trace_afs_cb_break(&vnode->fid, vnode->cb_break, reason, false); | ||
226 | } | 230 | } |
227 | } | 231 | } |
228 | 232 | ||
229 | void afs_break_callback(struct afs_vnode *vnode) | 233 | void afs_break_callback(struct afs_vnode *vnode, enum afs_cb_break_reason reason) |
230 | { | 234 | { |
231 | write_seqlock(&vnode->cb_lock); | 235 | write_seqlock(&vnode->cb_lock); |
232 | __afs_break_callback(vnode); | 236 | __afs_break_callback(vnode, reason); |
233 | write_sequnlock(&vnode->cb_lock); | 237 | write_sequnlock(&vnode->cb_lock); |
234 | } | 238 | } |
235 | 239 | ||
@@ -277,6 +281,8 @@ static void afs_break_one_callback(struct afs_server *server, | |||
277 | 281 | ||
278 | write_lock(&volume->cb_v_break_lock); | 282 | write_lock(&volume->cb_v_break_lock); |
279 | volume->cb_v_break++; | 283 | volume->cb_v_break++; |
284 | trace_afs_cb_break(fid, volume->cb_v_break, | ||
285 | afs_cb_break_for_volume_callback, false); | ||
280 | write_unlock(&volume->cb_v_break_lock); | 286 | write_unlock(&volume->cb_v_break_lock); |
281 | } else { | 287 | } else { |
282 | data.volume = NULL; | 288 | data.volume = NULL; |
@@ -285,8 +291,10 @@ static void afs_break_one_callback(struct afs_server *server, | |||
285 | afs_iget5_test, &data); | 291 | afs_iget5_test, &data); |
286 | if (inode) { | 292 | if (inode) { |
287 | vnode = AFS_FS_I(inode); | 293 | vnode = AFS_FS_I(inode); |
288 | afs_break_callback(vnode); | 294 | afs_break_callback(vnode, afs_cb_break_for_callback); |
289 | iput(inode); | 295 | iput(inode); |
296 | } else { | ||
297 | trace_afs_cb_miss(fid, afs_cb_break_for_callback); | ||
290 | } | 298 | } |
291 | } | 299 | } |
292 | } | 300 | } |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 93fd51c3bdae..e8c58c94eb61 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -1367,12 +1367,12 @@ static int afs_dir_remove_link(struct afs_vnode *dvnode, struct dentry *dentry, | |||
1367 | drop_nlink(&vnode->vfs_inode); | 1367 | drop_nlink(&vnode->vfs_inode); |
1368 | if (vnode->vfs_inode.i_nlink == 0) { | 1368 | if (vnode->vfs_inode.i_nlink == 0) { |
1369 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 1369 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
1370 | __afs_break_callback(vnode); | 1370 | __afs_break_callback(vnode, afs_cb_break_for_unlink); |
1371 | } | 1371 | } |
1372 | write_sequnlock(&vnode->cb_lock); | 1372 | write_sequnlock(&vnode->cb_lock); |
1373 | ret = 0; | 1373 | ret = 0; |
1374 | } else { | 1374 | } else { |
1375 | afs_break_callback(vnode); | 1375 | afs_break_callback(vnode, afs_cb_break_for_unlink); |
1376 | 1376 | ||
1377 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) | 1377 | if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) |
1378 | kdebug("AFS_VNODE_DELETED"); | 1378 | kdebug("AFS_VNODE_DELETED"); |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 18a50d4febcf..7b1c18c32f48 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -283,7 +283,7 @@ void afs_vnode_commit_status(struct afs_fs_cursor *fc, | |||
283 | if (scb->status.abort_code == VNOVNODE) { | 283 | if (scb->status.abort_code == VNOVNODE) { |
284 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 284 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
285 | clear_nlink(&vnode->vfs_inode); | 285 | clear_nlink(&vnode->vfs_inode); |
286 | __afs_break_callback(vnode); | 286 | __afs_break_callback(vnode, afs_cb_break_for_deleted); |
287 | } | 287 | } |
288 | } else { | 288 | } else { |
289 | if (scb->have_status) | 289 | if (scb->have_status) |
@@ -594,8 +594,9 @@ bool afs_check_validity(struct afs_vnode *vnode) | |||
594 | struct afs_cb_interest *cbi; | 594 | struct afs_cb_interest *cbi; |
595 | struct afs_server *server; | 595 | struct afs_server *server; |
596 | struct afs_volume *volume = vnode->volume; | 596 | struct afs_volume *volume = vnode->volume; |
597 | enum afs_cb_break_reason need_clear = afs_cb_break_no_break; | ||
597 | time64_t now = ktime_get_real_seconds(); | 598 | time64_t now = ktime_get_real_seconds(); |
598 | bool valid, need_clear = false; | 599 | bool valid; |
599 | unsigned int cb_break, cb_s_break, cb_v_break; | 600 | unsigned int cb_break, cb_s_break, cb_v_break; |
600 | int seq = 0; | 601 | int seq = 0; |
601 | 602 | ||
@@ -613,13 +614,13 @@ bool afs_check_validity(struct afs_vnode *vnode) | |||
613 | vnode->cb_v_break != cb_v_break) { | 614 | vnode->cb_v_break != cb_v_break) { |
614 | vnode->cb_s_break = cb_s_break; | 615 | vnode->cb_s_break = cb_s_break; |
615 | vnode->cb_v_break = cb_v_break; | 616 | vnode->cb_v_break = cb_v_break; |
616 | need_clear = true; | 617 | need_clear = afs_cb_break_for_vsbreak; |
617 | valid = false; | 618 | valid = false; |
618 | } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | 619 | } else if (test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { |
619 | need_clear = true; | 620 | need_clear = afs_cb_break_for_zap; |
620 | valid = false; | 621 | valid = false; |
621 | } else if (vnode->cb_expires_at - 10 <= now) { | 622 | } else if (vnode->cb_expires_at - 10 <= now) { |
622 | need_clear = true; | 623 | need_clear = afs_cb_break_for_lapsed; |
623 | valid = false; | 624 | valid = false; |
624 | } else { | 625 | } else { |
625 | valid = true; | 626 | valid = true; |
@@ -635,10 +636,12 @@ bool afs_check_validity(struct afs_vnode *vnode) | |||
635 | 636 | ||
636 | done_seqretry(&vnode->cb_lock, seq); | 637 | done_seqretry(&vnode->cb_lock, seq); |
637 | 638 | ||
638 | if (need_clear) { | 639 | if (need_clear != afs_cb_break_no_break) { |
639 | write_seqlock(&vnode->cb_lock); | 640 | write_seqlock(&vnode->cb_lock); |
640 | if (cb_break == vnode->cb_break) | 641 | if (cb_break == vnode->cb_break) |
641 | __afs_break_callback(vnode); | 642 | __afs_break_callback(vnode, need_clear); |
643 | else | ||
644 | trace_afs_cb_miss(&vnode->fid, need_clear); | ||
642 | write_sequnlock(&vnode->cb_lock); | 645 | write_sequnlock(&vnode->cb_lock); |
643 | valid = false; | 646 | valid = false; |
644 | } | 647 | } |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 8252d69bd3e4..4d9b3e9a422a 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -848,9 +848,9 @@ extern struct fscache_cookie_def afs_vnode_cache_index_def; | |||
848 | * callback.c | 848 | * callback.c |
849 | */ | 849 | */ |
850 | extern void afs_init_callback_state(struct afs_server *); | 850 | extern void afs_init_callback_state(struct afs_server *); |
851 | extern void __afs_break_callback(struct afs_vnode *); | 851 | extern void __afs_break_callback(struct afs_vnode *, enum afs_cb_break_reason); |
852 | extern void afs_break_callback(struct afs_vnode *); | 852 | extern void afs_break_callback(struct afs_vnode *, enum afs_cb_break_reason); |
853 | extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break*); | 853 | extern void afs_break_callbacks(struct afs_server *, size_t, struct afs_callback_break *); |
854 | 854 | ||
855 | extern int afs_register_server_cb_interest(struct afs_vnode *, | 855 | extern int afs_register_server_cb_interest(struct afs_vnode *, |
856 | struct afs_server_list *, unsigned int); | 856 | struct afs_server_list *, unsigned int); |
@@ -1438,7 +1438,7 @@ static inline void afs_check_for_remote_deletion(struct afs_fs_cursor *fc, | |||
1438 | { | 1438 | { |
1439 | if (fc->ac.error == -ENOENT) { | 1439 | if (fc->ac.error == -ENOENT) { |
1440 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | 1440 | set_bit(AFS_VNODE_DELETED, &vnode->flags); |
1441 | afs_break_callback(vnode); | 1441 | afs_break_callback(vnode, afs_cb_break_for_deleted); |
1442 | } | 1442 | } |
1443 | } | 1443 | } |
1444 | 1444 | ||
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 562f854ac4bf..34628e207849 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h | |||
@@ -195,6 +195,17 @@ enum afs_flock_operation { | |||
195 | afs_flock_op_wake, | 195 | afs_flock_op_wake, |
196 | }; | 196 | }; |
197 | 197 | ||
198 | enum afs_cb_break_reason { | ||
199 | afs_cb_break_no_break, | ||
200 | afs_cb_break_for_callback, | ||
201 | afs_cb_break_for_deleted, | ||
202 | afs_cb_break_for_lapsed, | ||
203 | afs_cb_break_for_unlink, | ||
204 | afs_cb_break_for_vsbreak, | ||
205 | afs_cb_break_for_volume_callback, | ||
206 | afs_cb_break_for_zap, | ||
207 | }; | ||
208 | |||
198 | #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ | 209 | #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ |
199 | 210 | ||
200 | /* | 211 | /* |
@@ -374,6 +385,16 @@ enum afs_flock_operation { | |||
374 | EM(afs_flock_op_unlock, "UNLOCK ") \ | 385 | EM(afs_flock_op_unlock, "UNLOCK ") \ |
375 | E_(afs_flock_op_wake, "WAKE ") | 386 | E_(afs_flock_op_wake, "WAKE ") |
376 | 387 | ||
388 | #define afs_cb_break_reasons \ | ||
389 | EM(afs_cb_break_no_break, "no-break") \ | ||
390 | EM(afs_cb_break_for_callback, "break-cb") \ | ||
391 | EM(afs_cb_break_for_deleted, "break-del") \ | ||
392 | EM(afs_cb_break_for_lapsed, "break-lapsed") \ | ||
393 | EM(afs_cb_break_for_unlink, "break-unlink") \ | ||
394 | EM(afs_cb_break_for_vsbreak, "break-vs") \ | ||
395 | EM(afs_cb_break_for_volume_callback, "break-v-cb") \ | ||
396 | E_(afs_cb_break_for_zap, "break-zap") | ||
397 | |||
377 | /* | 398 | /* |
378 | * Export enum symbols via userspace. | 399 | * Export enum symbols via userspace. |
379 | */ | 400 | */ |
@@ -392,6 +413,7 @@ afs_io_errors; | |||
392 | afs_file_errors; | 413 | afs_file_errors; |
393 | afs_flock_types; | 414 | afs_flock_types; |
394 | afs_flock_operations; | 415 | afs_flock_operations; |
416 | afs_cb_break_reasons; | ||
395 | 417 | ||
396 | /* | 418 | /* |
397 | * Now redefine the EM() and E_() macros to map the enums to the strings that | 419 | * Now redefine the EM() and E_() macros to map the enums to the strings that |
@@ -1171,6 +1193,53 @@ TRACE_EVENT(afs_get_tree, | |||
1171 | __entry->cell, __entry->volume, __entry->vid) | 1193 | __entry->cell, __entry->volume, __entry->vid) |
1172 | ); | 1194 | ); |
1173 | 1195 | ||
1196 | TRACE_EVENT(afs_cb_break, | ||
1197 | TP_PROTO(struct afs_fid *fid, unsigned int cb_break, | ||
1198 | enum afs_cb_break_reason reason, bool skipped), | ||
1199 | |||
1200 | TP_ARGS(fid, cb_break, reason, skipped), | ||
1201 | |||
1202 | TP_STRUCT__entry( | ||
1203 | __field_struct(struct afs_fid, fid ) | ||
1204 | __field(unsigned int, cb_break ) | ||
1205 | __field(enum afs_cb_break_reason, reason ) | ||
1206 | __field(bool, skipped ) | ||
1207 | ), | ||
1208 | |||
1209 | TP_fast_assign( | ||
1210 | __entry->fid = *fid; | ||
1211 | __entry->cb_break = cb_break; | ||
1212 | __entry->reason = reason; | ||
1213 | __entry->skipped = skipped; | ||
1214 | ), | ||
1215 | |||
1216 | TP_printk("%llx:%llx:%x b=%x s=%u %s", | ||
1217 | __entry->fid.vid, __entry->fid.vnode, __entry->fid.unique, | ||
1218 | __entry->cb_break, | ||
1219 | __entry->skipped, | ||
1220 | __print_symbolic(__entry->reason, afs_cb_break_reasons)) | ||
1221 | ); | ||
1222 | |||
1223 | TRACE_EVENT(afs_cb_miss, | ||
1224 | TP_PROTO(struct afs_fid *fid, enum afs_cb_break_reason reason), | ||
1225 | |||
1226 | TP_ARGS(fid, reason), | ||
1227 | |||
1228 | TP_STRUCT__entry( | ||
1229 | __field_struct(struct afs_fid, fid ) | ||
1230 | __field(enum afs_cb_break_reason, reason ) | ||
1231 | ), | ||
1232 | |||
1233 | TP_fast_assign( | ||
1234 | __entry->fid = *fid; | ||
1235 | __entry->reason = reason; | ||
1236 | ), | ||
1237 | |||
1238 | TP_printk(" %llx:%llx:%x %s", | ||
1239 | __entry->fid.vid, __entry->fid.vnode, __entry->fid.unique, | ||
1240 | __print_symbolic(__entry->reason, afs_cb_break_reasons)) | ||
1241 | ); | ||
1242 | |||
1174 | #endif /* _TRACE_AFS_H */ | 1243 | #endif /* _TRACE_AFS_H */ |
1175 | 1244 | ||
1176 | /* This part must be outside protection */ | 1245 | /* This part must be outside protection */ |