2222#include "xfs_healthmon.h"
2323#include "xfs_fsops.h"
2424#include "xfs_notify_failure.h"
25+ #include "xfs_file.h"
2526
2627#include <linux/anon_inodes.h>
2728#include <linux/eventpoll.h>
2829#include <linux/poll.h>
30+ #include <linux/fserror.h>
2931
3032/*
3133 * Live Health Monitoring
@@ -222,6 +224,27 @@ xfs_healthmon_merge_events(
222224 return true;
223225 }
224226 return false;
227+
228+ case XFS_HEALTHMON_BUFREAD :
229+ case XFS_HEALTHMON_BUFWRITE :
230+ case XFS_HEALTHMON_DIOREAD :
231+ case XFS_HEALTHMON_DIOWRITE :
232+ case XFS_HEALTHMON_DATALOST :
233+ /* logically adjacent file ranges can merge */
234+ if (existing -> fino != new -> fino || existing -> fgen != new -> fgen )
235+ return false;
236+
237+ if (existing -> fpos + existing -> flen == new -> fpos ) {
238+ existing -> flen += new -> flen ;
239+ return true;
240+ }
241+
242+ if (new -> fpos + new -> flen == existing -> fpos ) {
243+ existing -> fpos = new -> fpos ;
244+ existing -> flen += new -> flen ;
245+ return true;
246+ }
247+ return false;
225248 }
226249
227250 return false;
@@ -578,6 +601,55 @@ xfs_healthmon_report_media(
578601 xfs_healthmon_put (hm );
579602}
580603
604+ static inline enum xfs_healthmon_type file_ioerr_type (enum fserror_type action )
605+ {
606+ switch (action ) {
607+ case FSERR_BUFFERED_READ :
608+ return XFS_HEALTHMON_BUFREAD ;
609+ case FSERR_BUFFERED_WRITE :
610+ return XFS_HEALTHMON_BUFWRITE ;
611+ case FSERR_DIRECTIO_READ :
612+ return XFS_HEALTHMON_DIOREAD ;
613+ case FSERR_DIRECTIO_WRITE :
614+ return XFS_HEALTHMON_DIOWRITE ;
615+ case FSERR_DATA_LOST :
616+ return XFS_HEALTHMON_DATALOST ;
617+ case FSERR_METADATA :
618+ /* filtered out by xfs_fs_report_error */
619+ break ;
620+ }
621+
622+ ASSERT (0 );
623+ return -1 ;
624+ }
625+
626+ /* Add a file io error event to the reporting queue. */
627+ void
628+ xfs_healthmon_report_file_ioerror (
629+ struct xfs_inode * ip ,
630+ const struct fserror_event * p )
631+ {
632+ struct xfs_healthmon_event event = {
633+ .type = file_ioerr_type (p -> type ),
634+ .domain = XFS_HEALTHMON_FILERANGE ,
635+ .fino = ip -> i_ino ,
636+ .fgen = VFS_I (ip )-> i_generation ,
637+ .fpos = p -> pos ,
638+ .flen = p -> len ,
639+ /* send positive error number to userspace */
640+ .error = - p -> error ,
641+ };
642+ struct xfs_healthmon * hm = xfs_healthmon_get (ip -> i_mount );
643+
644+ if (!hm )
645+ return ;
646+
647+ trace_xfs_healthmon_report_file_ioerror (hm , p );
648+
649+ xfs_healthmon_push (hm , & event );
650+ xfs_healthmon_put (hm );
651+ }
652+
581653static inline void
582654xfs_healthmon_reset_outbuf (
583655 struct xfs_healthmon * hm )
@@ -633,6 +705,7 @@ static const unsigned int domain_map[] = {
633705 [XFS_HEALTHMON_DATADEV ] = XFS_HEALTH_MONITOR_DOMAIN_DATADEV ,
634706 [XFS_HEALTHMON_RTDEV ] = XFS_HEALTH_MONITOR_DOMAIN_RTDEV ,
635707 [XFS_HEALTHMON_LOGDEV ] = XFS_HEALTH_MONITOR_DOMAIN_LOGDEV ,
708+ [XFS_HEALTHMON_FILERANGE ] = XFS_HEALTH_MONITOR_DOMAIN_FILERANGE ,
636709};
637710
638711static const unsigned int type_map [] = {
@@ -644,6 +717,11 @@ static const unsigned int type_map[] = {
644717 [XFS_HEALTHMON_UNMOUNT ] = XFS_HEALTH_MONITOR_TYPE_UNMOUNT ,
645718 [XFS_HEALTHMON_SHUTDOWN ] = XFS_HEALTH_MONITOR_TYPE_SHUTDOWN ,
646719 [XFS_HEALTHMON_MEDIA_ERROR ] = XFS_HEALTH_MONITOR_TYPE_MEDIA_ERROR ,
720+ [XFS_HEALTHMON_BUFREAD ] = XFS_HEALTH_MONITOR_TYPE_BUFREAD ,
721+ [XFS_HEALTHMON_BUFWRITE ] = XFS_HEALTH_MONITOR_TYPE_BUFWRITE ,
722+ [XFS_HEALTHMON_DIOREAD ] = XFS_HEALTH_MONITOR_TYPE_DIOREAD ,
723+ [XFS_HEALTHMON_DIOWRITE ] = XFS_HEALTH_MONITOR_TYPE_DIOWRITE ,
724+ [XFS_HEALTHMON_DATALOST ] = XFS_HEALTH_MONITOR_TYPE_DATALOST ,
647725};
648726
649727/* Render event as a V0 structure */
@@ -701,6 +779,13 @@ xfs_healthmon_format_v0(
701779 hme .e .media .daddr = event -> daddr ;
702780 hme .e .media .bbcount = event -> bbcount ;
703781 break ;
782+ case XFS_HEALTHMON_FILERANGE :
783+ hme .e .filerange .ino = event -> fino ;
784+ hme .e .filerange .gen = event -> fgen ;
785+ hme .e .filerange .pos = event -> fpos ;
786+ hme .e .filerange .len = event -> flen ;
787+ hme .e .filerange .error = abs (event -> error );
788+ break ;
704789 default :
705790 break ;
706791 }
0 commit comments