2 * Copyright (C) 2003-2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
32 #include <sys/dirent.h>
34 #include <sys/mount.h>
35 #include <sys/vnode.h>
36 #include <sys/malloc.h>
38 #include <sys/quota.h>
40 #include <sys/kdebug.h>
43 #include "hfs_catalog.h"
44 #include "hfs_cnode.h"
46 #include "hfs_mount.h"
47 #include "hfs_quota.h"
48 #include "hfs_endian.h"
50 #include "BTreesInternal.h"
51 #include "FileMgrInternal.h"
55 void hfs_generate_volume_notifications(struct hfsmount
*hfsmp
)
58 u_int32_t freeblks
, state
=999;
60 /* Do not generate low disk notifications for read-only volumes */
61 if (hfsmp
->hfs_flags
& HFS_READ_ONLY
) {
65 fsid
.val
[0] = hfsmp
->hfs_raw_dev
;
66 fsid
.val
[1] = vfs_typenum(HFSTOVFS(hfsmp
));
68 freeblks
= hfs_freeblks(hfsmp
, 1);
71 * Find the theshold the number of free blocks fits into.
72 * We fire upon reaching a level below desired only once,
73 * except for when we reach the low disk or near low disk levels
74 * from below, in which case we do not fire unless we have also
75 * reached the desired disk level (hysteresis).
76 * This is illustrated in the following diagram:
79 * --------- desired level
84 * --------- near low disk level
89 * --------- low disk level
94 * --------- very low disk level
98 if (freeblks
< hfsmp
->hfs_freespace_notify_dangerlimit
) {
100 } else if (freeblks
< hfsmp
->hfs_freespace_notify_warninglimit
) {
102 } else if (freeblks
< hfsmp
->hfs_freespace_notify_nearwarninglimit
) {
104 } else if (freeblks
< hfsmp
->hfs_freespace_notify_desiredlevel
) {
105 /* We are between the near low disk and desired levels */
107 } else if (freeblks
>= hfsmp
->hfs_freespace_notify_desiredlevel
) {
111 /* Free blocks are less than dangerlimit for the first time */
112 if (state
== 4 && !(hfsmp
->hfs_notification_conditions
& VQ_VERYLOWDISK
)) {
113 /* Dump some logging to track down intermittent issues */
114 printf("hfs: set VeryLowDisk: vol:%s, freeblks:%d, dangerlimit:%d\n", hfsmp
->vcbVN
, freeblks
, hfsmp
->hfs_freespace_notify_dangerlimit
);
117 // If we're a sparse device, dump some info about the backing store..
118 hfs_lock_mount(hfsmp
);
119 vnode_t backing_vp
= hfsmp
->hfs_backingvp
;
120 if (backing_vp
&& vnode_get(backing_vp
) != 0)
122 hfs_unlock_mount(hfsmp
);
125 struct vfsstatfs
*sfs
= vfs_statfs(vnode_mount(backing_vp
));
126 printf("hfs: set VeryLowDisk: vol:%s, backingstore b_avail:%lld, tag:%d\n",
127 hfsmp
->vcbVN
, sfs
->f_bavail
, vnode_tag(backing_vp
));
128 vnode_put(backing_vp
);
132 hfsmp
->hfs_notification_conditions
|= (VQ_VERYLOWDISK
|VQ_LOWDISK
|VQ_NEARLOWDISK
);
133 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);
134 } else if (state
== 3) {
135 /* Free blocks are less than warning limit for the first time */
136 if (!(hfsmp
->hfs_notification_conditions
& VQ_LOWDISK
)) {
137 printf("hfs: set LowDisk: vol:%s, freeblks:%d, warninglimit:%d\n", hfsmp
->vcbVN
, freeblks
, hfsmp
->hfs_freespace_notify_warninglimit
);
138 hfsmp
->hfs_notification_conditions
|= (VQ_LOWDISK
|VQ_NEARLOWDISK
);
139 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);
140 } else if (hfsmp
->hfs_notification_conditions
& VQ_VERYLOWDISK
) {
141 /* Free blocks count has increased from danger limit to warning limit, so just clear VERYLOWDISK warning */
142 printf("hfs: clear VeryLowDisk: vol:%s, freeblks:%d, dangerlimit:%d\n", hfsmp
->vcbVN
, freeblks
, hfsmp
->hfs_freespace_notify_dangerlimit
);
143 hfsmp
->hfs_notification_conditions
&= ~VQ_VERYLOWDISK
;
144 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);
146 } else if (state
== 2) {
147 /* Free blocks are less than the near warning limit for the first time */
148 if (!(hfsmp
->hfs_notification_conditions
& VQ_NEARLOWDISK
)) {
149 printf("hfs: set NearLowDisk: vol:%s, freeblks:%d, nearwarninglimit:%d\n", hfsmp
->vcbVN
, freeblks
,
150 hfsmp
->hfs_freespace_notify_nearwarninglimit
);
152 hfsmp
->hfs_notification_conditions
|= VQ_NEARLOWDISK
;
153 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);
155 /* Free blocks count has increased from warning/danger limit to near warning limit,
156 * so clear VERYLOWDISK / LOWDISK warnings, and signal if we clear VERYLOWDISK */
157 hfsmp
->hfs_notification_conditions
&= ~VQ_LOWDISK
;
158 if (hfsmp
->hfs_notification_conditions
& VQ_VERYLOWDISK
) {
159 printf("hfs: clear VeryLowDisk: vol:%s, freeblks:%d, dangerlimit:%d\n", hfsmp
->vcbVN
, freeblks
,
160 hfsmp
->hfs_freespace_notify_dangerlimit
);
162 hfsmp
->hfs_notification_conditions
&= ~VQ_VERYLOWDISK
;
163 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);
166 } else if (state
== 1) {
167 /* Free blocks are less than the desireable level, but more than the near warning level
168 * In this case, we may have to notify if we were previously underneath the danger limit */
169 if (hfsmp
->hfs_notification_conditions
& VQ_VERYLOWDISK
) {
170 printf("hfs: clear VeryLowDisk: vol:%s, freeblks:%d, dangerlimit:%d\n", hfsmp
->vcbVN
, freeblks
,
171 hfsmp
->hfs_freespace_notify_dangerlimit
);
173 hfsmp
->hfs_notification_conditions
&= ~VQ_VERYLOWDISK
;
174 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);
176 } else if (state
== 0) {
177 /* Free blocks count has increased to desirable level, so clear all conditions */
178 if (hfsmp
->hfs_notification_conditions
& (VQ_NEARLOWDISK
|VQ_LOWDISK
|VQ_VERYLOWDISK
)) {
179 if (hfsmp
->hfs_notification_conditions
& VQ_NEARLOWDISK
) {
180 printf("hfs: clear NearLowDisk: vol:%s, freeblks:%d, nearwarninglimit:%d, desiredlevel:%d\n", hfsmp
->vcbVN
,
181 freeblks
, hfsmp
->hfs_freespace_notify_nearwarninglimit
, hfsmp
->hfs_freespace_notify_desiredlevel
);
183 if (hfsmp
->hfs_notification_conditions
& VQ_LOWDISK
) {
184 printf("hfs: clear LowDisk: vol:%s, freeblks:%d, warninglimit:%d, desiredlevel:%d\n", hfsmp
->vcbVN
, freeblks
,
185 hfsmp
->hfs_freespace_notify_warninglimit
, hfsmp
->hfs_freespace_notify_desiredlevel
);
187 if (hfsmp
->hfs_notification_conditions
& VQ_VERYLOWDISK
) {
188 printf("hfs: clear VeryLowDisk: vol:%s, freeblks:%d, dangerlimit:%d\n", hfsmp
->vcbVN
, freeblks
, hfsmp
->hfs_freespace_notify_warninglimit
);
190 hfsmp
->hfs_notification_conditions
&= ~(VQ_VERYLOWDISK
|VQ_LOWDISK
|VQ_NEARLOWDISK
);
191 if (hfsmp
->hfs_notification_conditions
== 0) {
192 vfs_event_signal(&fsid
, VQ_UPDATE
|VQ_DESIRED_DISK
, (intptr_t)NULL
);
194 vfs_event_signal(&fsid
, hfsmp
->hfs_notification_conditions
, (intptr_t)NULL
);