]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - cddl/usr.sbin/zfsd/case_file.h
Update edk2 headers to stable202005
[FreeBSD/FreeBSD.git] / cddl / usr.sbin / zfsd / case_file.h
1 /*-
2  * Copyright (c) 2011, 2012, 2013 Spectra Logic Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    substantially similar to the "NO WARRANTY" disclaimer below
13  *    ("Disclaimer") and any redistribution must be conditioned upon
14  *    including a substantially similar Disclaimer requirement for further
15  *    binary redistribution.
16  *
17  * NO WARRANTY
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGES.
29  *
30  * Authors: Justin T. Gibbs     (Spectra Logic Corporation)
31  *
32  * $FreeBSD$
33  */
34
35 /**
36  * \file case_file.h
37  *
38  * CaseFile objects aggregate vdev faults that may require ZFSD action
39  * in order to maintain the health of a ZFS pool.
40  *
41  * Header requirements:
42  *
43  *    #include <list>
44  *
45  *    #include "callout.h"
46  *    #include "zfsd_event.h"
47  */
48 #ifndef _CASE_FILE_H_
49 #define _CASE_FILE_H_
50
51 /*=========================== Forward Declarations ===========================*/
52 class CaseFile;
53 class Vdev;
54
55 /*============================= Class Definitions ============================*/
56 /*------------------------------- CaseFileList -------------------------------*/
57 /**
58  * CaseFileList is a specialization of the standard list STL container.
59  */
60 typedef std::list< CaseFile *> CaseFileList;
61
62 /*--------------------------------- CaseFile ---------------------------------*/
63 /**
64  * A CaseFile object is instantiated anytime a vdev for an active pool
65  * experiences an I/O error, is faulted by ZFS, or is determined to be
66  * missing/removed.
67  *
68  * A vdev may have at most one CaseFile.
69  *
70  * CaseFiles are retired when a vdev leaves an active pool configuration
71  * or an action is taken to resolve the issues recorded in the CaseFile.
72  *
73  * Logging a case against a vdev does not imply that an immediate action
74  * to resolve a fault is required or even desired.  For example, a CaseFile
75  * must accumulate a number of I/O errors in order to flag a device as
76  * degraded.
77  *
78  * Vdev I/O errors are not recorded in ZFS label inforamation.  For this
79  * reasons, CaseFile%%s with accumulated I/O error events are serialized
80  * to the file system so that they survive across boots.  Currently all
81  * other fault types can be reconstructed from ZFS label information, so
82  * CaseFile%%s for missing, faulted, or degradded members are just recreated
83  * at ZFSD startup instead of being deserialized from the file system.
84  */
85 class CaseFile
86 {
87 public:
88         /**
89          * \brief Find a CaseFile object by a vdev's pool/vdev GUID tuple.
90          *
91          * \param poolGUID  Pool GUID for the vdev of the CaseFile to find.
92          *                  If InvalidGuid, then only match the vdev GUID
93          *                  instead of both pool and vdev GUIDs.
94          * \param vdevGUID  Vdev GUID for the vdev of the CaseFile to find.
95          *
96          * \return  If found, a pointer to a valid CaseFile object.
97          *          Otherwise NULL.
98          */
99         static CaseFile *Find(DevdCtl::Guid poolGUID, DevdCtl::Guid vdevGUID);
100
101         /**
102          * \brief Find a CaseFile object by a vdev's current/last known
103          *        physical path.
104          *
105          * \param physPath  Physical path of the vdev of the CaseFile to find.
106          *
107          * \return  If found, a pointer to a valid CaseFile object.
108          *          Otherwise NULL.
109          */
110         static CaseFile *Find(const string &physPath);
111
112         /**
113          * \brief ReEvaluate all open cases whose pool guid matches the argument
114          *
115          * \param poolGUID      Only reevaluate cases for this pool
116          * \param event         Try to consume this event with the casefile
117          */
118         static void ReEvaluateByGuid(DevdCtl::Guid poolGUID,
119                                      const ZfsEvent &event);
120
121         /**
122          * \brief Create or return an existing active CaseFile for the
123          *        specified vdev.
124          *
125          * \param vdev  The vdev object for which to find/create a CaseFile.
126          *
127          * \return  A reference to a valid CaseFile object.
128          */
129         static CaseFile &Create(Vdev &vdev);
130
131         /**
132          * \brief Deserialize all serialized CaseFile objects found in
133          *        the file system.
134          */
135         static void      DeSerialize();
136
137         /**
138          * \brief returns true if there are no CaseFiles
139          */
140         static bool     Empty();
141
142         /**
143          * \brief Emit syslog data on all active CaseFile%%s in the system.
144          */
145         static void      LogAll();
146
147         /**
148          * \brief Destroy the in-core cache of CaseFile data.
149          *
150          * This routine does not disturb the on disk, serialized, CaseFile
151          * data.
152          */
153         static void      PurgeAll();
154
155         DevdCtl::Guid PoolGUID()       const;
156         DevdCtl::Guid VdevGUID()       const;
157         vdev_state    VdevState()      const;
158         const string &PoolGUIDString() const;
159         const string &VdevGUIDString() const;
160         const string &PhysicalPath()   const;
161
162         /**
163          * \brief Attempt to resolve this CaseFile using the disk
164          *        resource at the given device/physical path/vdev object
165          *        tuple.
166          *
167          * \param devPath   The devfs path for the disk resource.
168          * \param physPath  The physical path information reported by
169          *                  the disk resource.
170          * \param vdev      If the disk contains ZFS label information,
171          *                  a pointer to the disk label's vdev object
172          *                  data.  Otherwise NULL.
173          *
174          * \return  True if this event was consumed by this CaseFile.
175          */
176         bool ReEvaluate(const string &devPath, const string &physPath,
177                         Vdev *vdev);
178
179         /**
180          * \brief Update this CaseFile in light of the provided ZfsEvent.
181          *
182          * Must be virtual so it can be overridden in the unit tests
183          *
184          * \param event  The ZfsEvent to evaluate.
185          *
186          * \return  True if this event was consumed by this CaseFile.
187          */
188         virtual bool ReEvaluate(const ZfsEvent &event);
189
190         /**
191          * \brief Register an itimer callout for the given event, if necessary
192          */
193         virtual void RegisterCallout(const DevdCtl::Event &event);
194
195         /**
196          * \brief Close a case if it is no longer relevant.
197          *
198          * This method deals with cases tracking soft errors.  Soft errors
199          * will be discarded should a remove event occur within a short period
200          * of the soft errors being reported.  We also discard the events
201          * if the vdev is marked degraded or failed.
202          *
203          * \return  True if the case is closed.  False otherwise.
204          */
205         bool CloseIfSolved();
206
207         /**
208          * \brief Emit data about this CaseFile via syslog(3).
209          */
210         void Log();
211
212         /**
213          * \brief Whether we should degrade this vdev
214          */
215         bool ShouldDegrade() const;
216
217         /**
218          * \brief Whether we should fault this vdev
219          */
220         bool ShouldFault() const;
221
222 protected:
223         enum {
224                 /**
225                  * The number of soft errors on a vdev required
226                  * to transition a vdev from healthy to degraded
227                  * status.
228                  */
229                 ZFS_DEGRADE_IO_COUNT = 50
230         };
231
232         static CalloutFunc_t OnGracePeriodEnded;
233
234         /**
235          * \brief scandir(3) filter function used to find files containing
236          *        serialized CaseFile data.
237          *
238          * \param dirEntry  Directory entry for the file to filter.
239          *
240          * \return  Non-zero for a file to include in the selection,
241          *          otherwise 0.
242          */
243         static int  DeSerializeSelector(const struct dirent *dirEntry);
244
245         /**
246          * \brief Given the name of a file containing serialized events from a
247          *        CaseFile object, create/update an in-core CaseFile object
248          *        representing the serialized data.
249          *
250          * \param fileName  The name of a file containing serialized events
251          *                  from a CaseFile object.
252          */
253         static void DeSerializeFile(const char *fileName);
254
255         /** Constructor. */
256         CaseFile(const Vdev &vdev);
257
258         /**
259          * Destructor.
260          * Must be virtual so it can be subclassed in the unit tests
261          */
262         virtual ~CaseFile();
263
264         /**
265          * \brief Reload state for the vdev associated with this CaseFile.
266          *
267          * \return  True if the refresh was successful.  False if the system
268          *          has no record of the pool or vdev for this CaseFile.
269          */
270         virtual bool RefreshVdevState();
271
272         /**
273          * \brief Free all events in the m_events list.
274          */
275         void PurgeEvents();
276
277         /**
278          * \brief Free all events in the m_tentativeEvents list.
279          */
280         void PurgeTentativeEvents();
281
282         /**
283          * \brief Commit to file system storage.
284          */
285         void Serialize();
286
287         /**
288          * \brief Retrieve event data from a serialization stream.
289          *
290          * \param caseStream  The serializtion stream to parse.
291          */
292         void DeSerialize(std::ifstream &caseStream);
293
294         /**
295          * \brief Serializes the supplied event list and writes it to fd
296          *
297          * \param prefix  If not NULL, this prefix will be prepended to
298          *                every event in the file.
299          */
300         void SerializeEvList(const DevdCtl::EventList events, int fd,
301                              const char* prefix=NULL) const;
302
303         /**
304          * \brief Unconditionally close a CaseFile.
305          */
306         virtual void Close();
307
308         /**
309          * \brief Callout callback invoked when the remove timer grace
310          *        period expires.
311          *
312          * If no remove events are received prior to the grace period
313          * firing, then any tentative events are promoted and counted
314          * against the health of the vdev.
315          */
316         void OnGracePeriodEnded();
317
318         /**
319          * \brief Attempt to activate a spare on this case's pool.
320          *
321          * Call this whenever a pool becomes degraded.  It will look for any
322          * spare devices and activate one to replace the casefile's vdev.  It
323          * will _not_ close the casefile; that should only happen when the
324          * missing drive is replaced or the user promotes the spare.
325          *
326          * \return True if a spare was activated
327          */
328         bool ActivateSpare();
329
330         /**
331          * \brief replace a pool's vdev with another
332          *
333          * \param vdev_type   The type of the new vdev.  Usually either
334          *                    VDEV_TYPE_DISK or VDEV_TYPE_FILE
335          * \param path        The file system path to the new vdev
336          * \param isspare     Whether the new vdev is a spare
337          *
338          * \return            true iff the replacement was successful
339          */
340         bool Replace(const char* vdev_type, const char* path, bool isspare);
341
342         /**
343          * \brief Which vdev, if any, is replacing ours.
344          *
345          * \param zhp           Pool handle state from the caller context
346          *
347          * \return              the vdev that is currently replacing ours,
348          *                      or NonexistentVdev if there isn't one.
349          */
350         Vdev BeingReplacedBy(zpool_handle_t *zhp);
351
352         /**
353          * \brief All CaseFiles being tracked by ZFSD.
354          */
355         static CaseFileList  s_activeCases;
356
357         /**
358          * \brief The file system path to serialized CaseFile data.
359          */
360         static const string  s_caseFilePath;
361
362         /**
363          * \brief The time ZFSD waits before promoting a tentative event
364          *        into a permanent event.
365          */
366         static const timeval s_removeGracePeriod;
367
368         /**
369          * \brief A list of soft error events counted against the health of
370          *        a vdev.
371          */
372         DevdCtl::EventList m_events;
373
374         /**
375          * \brief A list of soft error events waiting for a grace period
376          *        expiration before being counted against the health of
377          *        a vdev.
378          */
379         DevdCtl::EventList m_tentativeEvents;
380
381         DevdCtl::Guid      m_poolGUID;
382         DevdCtl::Guid      m_vdevGUID;
383         vdev_state         m_vdevState;
384         string             m_poolGUIDString;
385         string             m_vdevGUIDString;
386         string             m_vdevPhysPath;
387
388         /**
389          * \brief Callout activated when a grace period
390          */
391         Callout           m_tentativeTimer;
392
393 private:
394         nvlist_t        *CaseVdev(zpool_handle_t *zhp)  const;
395 };
396
397 inline DevdCtl::Guid
398 CaseFile::PoolGUID() const
399 {
400         return (m_poolGUID);
401 }
402
403 inline DevdCtl::Guid
404 CaseFile::VdevGUID() const
405 {
406         return (m_vdevGUID);
407 }
408
409 inline vdev_state
410 CaseFile::VdevState() const
411 {
412         return (m_vdevState);
413 }
414
415 inline const string &
416 CaseFile::PoolGUIDString() const
417 {
418         return (m_poolGUIDString);
419 }
420
421 inline const string &
422 CaseFile::VdevGUIDString() const
423 {
424         return (m_vdevGUIDString);
425 }
426
427 inline const string &
428 CaseFile::PhysicalPath() const
429 {
430         return (m_vdevPhysPath);
431 }
432
433 #endif /* _CASE_FILE_H_ */