Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmgquota.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1993 Microsoft Corporation 00004 00005 Module Name: 00006 00007 cmgquota.c 00008 00009 Abstract: 00010 00011 The module contains CM routines to support Global Quota 00012 00013 Global Quota has little to do with NT's standard per-process/user 00014 quota system. Global Quota is waying of controlling the aggregate 00015 resource usage of the entire registry. It is used to manage space 00016 consumption by objects which user apps create, but which are persistent 00017 and therefore cannot be assigned to the quota of a user app. 00018 00019 Global Quota prevents the registry from consuming all of paged 00020 pool, and indirectly controls how much disk it can consume. 00021 Like the release 1 file systems, a single app can fill all the 00022 space in the registry, but at least it cannot kill the system. 00023 00024 Memory objects used for known short times and protected by 00025 serialization, or billable as quota objects, are not counted 00026 in the global quota. 00027 00028 Author: 00029 00030 Bryan M. Willman (bryanwi) 13-Jan-1993 00031 00032 Revision History: 00033 00034 --*/ 00035 00036 #include "cmp.h" 00037 00038 #ifdef ALLOC_PRAGMA 00039 #pragma alloc_text(PAGE,CmpClaimGlobalQuota) 00040 #pragma alloc_text(PAGE,CmpReleaseGlobalQuota) 00041 #pragma alloc_text(PAGE,CmpSetGlobalQuotaAllowed) 00042 #pragma alloc_text(PAGE,CmpQuotaWarningWorker) 00043 #pragma alloc_text(PAGE,CmQueryRegistryQuotaInformation) 00044 #pragma alloc_text(PAGE,CmSetRegistryQuotaInformation) 00045 #pragma alloc_text(INIT,CmpComputeGlobalQuotaAllowed) 00046 #endif 00047 00048 // 00049 // Registry control values 00050 // 00051 #define CM_DEFAULT_RATIO (3) 00052 #define CM_LIMIT_RATIO(x) ((x / 10) * 8) 00053 #define CM_MINIMUM_GLOBAL_QUOTA (16 *1024 * 1024) 00054 00055 // 00056 // Percent of used registry quota that triggers a hard error 00057 // warning popup. 00058 // 00059 #define CM_REGISTRY_WARNING_LEVEL (95) 00060 00061 extern ULONG CmRegistrySizeLimit; 00062 extern ULONG CmRegistrySizeLimitLength; 00063 extern ULONG CmRegistrySizeLimitType; 00064 00065 extern ULONG MmSizeOfPagedPoolInBytes; 00066 00067 // 00068 // Maximum number of bytes of Global Quota the registry may use. 00069 // Set to largest positive number for use in boot. Will be set down 00070 // based on pool and explicit registry values. 00071 // 00072 extern ULONG CmpGlobalQuota; 00073 extern ULONG CmpGlobalQuotaAllowed; 00074 00075 // 00076 // Mark that will trigger the low-on-quota popup 00077 // 00078 extern ULONG CmpGlobalQuotaWarning; 00079 00080 // 00081 // Indicate whether the popup has been triggered yet or not. 00082 // 00083 extern BOOLEAN CmpQuotaWarningPopupDisplayed; 00084 00085 // 00086 // GQ actually in use 00087 // 00088 extern ULONG CmpGlobalQuotaUsed; 00089 00090 00091 VOID 00092 CmQueryRegistryQuotaInformation( 00093 IN PSYSTEM_REGISTRY_QUOTA_INFORMATION RegistryQuotaInformation 00094 ) 00095 00096 /*++ 00097 00098 Routine Description: 00099 00100 Returns the registry quota information 00101 00102 Arguments: 00103 00104 RegistryQuotaInformation - Supplies pointer to buffer that will return 00105 the registry quota information. 00106 00107 Return Value: 00108 00109 None. 00110 00111 --*/ 00112 00113 { 00114 RegistryQuotaInformation->RegistryQuotaAllowed = CmpGlobalQuota; 00115 RegistryQuotaInformation->RegistryQuotaUsed = CmpGlobalQuotaUsed; 00116 RegistryQuotaInformation->PagedPoolSize = MmSizeOfPagedPoolInBytes; 00117 } 00118 00119 00120 VOID 00121 CmSetRegistryQuotaInformation( 00122 IN PSYSTEM_REGISTRY_QUOTA_INFORMATION RegistryQuotaInformation 00123 ) 00124 00125 /*++ 00126 00127 Routine Description: 00128 00129 Sets the registry quota information. The caller is assumed to have 00130 completed the necessary security checks already. 00131 00132 Arguments: 00133 00134 RegistryQuotaInformation - Supplies pointer to buffer that provides 00135 the new registry quota information. 00136 00137 Return Value: 00138 00139 None. 00140 00141 --*/ 00142 00143 { 00144 CmpGlobalQuota = RegistryQuotaInformation->RegistryQuotaAllowed; 00145 00146 // 00147 // Sanity checks against insane values 00148 // 00149 if (CmpGlobalQuota > CM_WRAP_LIMIT) { 00150 CmpGlobalQuota = CM_WRAP_LIMIT; 00151 } 00152 if (CmpGlobalQuota < CM_MINIMUM_GLOBAL_QUOTA) { 00153 CmpGlobalQuota = CM_MINIMUM_GLOBAL_QUOTA; 00154 } 00155 00156 // 00157 // Recompute the warning level 00158 // 00159 CmpGlobalQuotaWarning = CM_REGISTRY_WARNING_LEVEL * (CmpGlobalQuota / 100); 00160 00161 CmpGlobalQuotaAllowed = CmpGlobalQuota; 00162 } 00163 00164 00165 VOID 00166 CmpQuotaWarningWorker( 00167 IN PVOID WorkItem 00168 ) 00169 00170 /*++ 00171 00172 Routine Description: 00173 00174 Displays hard error popup that indicates the registry quota is 00175 running out. 00176 00177 Arguments: 00178 00179 WorkItem - Supplies pointer to the work item. This routine will 00180 free the work item. 00181 00182 Return Value: 00183 00184 None. 00185 00186 --*/ 00187 00188 { 00189 NTSTATUS Status; 00190 ULONG Response; 00191 00192 ExFreePool(WorkItem); 00193 00194 Status = ExRaiseHardError(STATUS_REGISTRY_QUOTA_LIMIT, 00195 0, 00196 0, 00197 NULL, 00198 OptionOk, 00199 &Response); 00200 } 00201 00202 00203 BOOLEAN 00204 CmpClaimGlobalQuota( 00205 IN ULONG Size 00206 ) 00207 /*++ 00208 00209 Routine Description: 00210 00211 If CmpGlobalQuotaUsed + Size >= CmpGlobalQuotaAllowed, return 00212 false. Otherwise, increment CmpGlobalQuotaUsed, in effect claiming 00213 the requested GlobalQuota. 00214 00215 Arguments: 00216 00217 Size - number of bytes of GlobalQuota caller wants to claim 00218 00219 Return Value: 00220 00221 TRUE - Claim succeeded, and has been counted in Used GQ 00222 00223 FALSE - Claim failed, nothing counted in GQ. 00224 00225 --*/ 00226 { 00227 LONG available; 00228 PWORK_QUEUE_ITEM WorkItem; 00229 00230 // 00231 // compute available space, then see if size <. This prevents overflows. 00232 // Note that this must be signed. Since quota is not enforced until logon, 00233 // it is possible for the available bytes to be negative. 00234 // 00235 00236 available = (LONG)CmpGlobalQuotaAllowed - (LONG)CmpGlobalQuotaUsed; 00237 00238 if ((LONG)Size < available) { 00239 CmpGlobalQuotaUsed += Size; 00240 if ((CmpGlobalQuotaUsed > CmpGlobalQuotaWarning) && 00241 (!CmpQuotaWarningPopupDisplayed) && 00242 (ExReadyForErrors)) { 00243 00244 // 00245 // Queue work item to display popup 00246 // 00247 WorkItem = ExAllocatePool(NonPagedPool, sizeof(WORK_QUEUE_ITEM)); 00248 if (WorkItem != NULL) { 00249 00250 CmpQuotaWarningPopupDisplayed = TRUE; 00251 ExInitializeWorkItem(WorkItem, 00252 CmpQuotaWarningWorker, 00253 WorkItem); 00254 ExQueueWorkItem(WorkItem, DelayedWorkQueue); 00255 } 00256 } 00257 return TRUE; 00258 } else { 00259 return FALSE; 00260 } 00261 } 00262 00263 00264 VOID 00265 CmpReleaseGlobalQuota( 00266 IN ULONG Size 00267 ) 00268 /*++ 00269 00270 Routine Description: 00271 00272 If Size <= CmpGlobalQuotaUsed, then decrement it. Else BugCheck. 00273 00274 Arguments: 00275 00276 Size - number of bytes of GlobalQuota caller wants to release 00277 00278 Return Value: 00279 00280 NONE. 00281 00282 --*/ 00283 { 00284 if (Size > CmpGlobalQuotaUsed) { 00285 KeBugCheckEx(REGISTRY_ERROR,2,1,0,0); 00286 } 00287 00288 CmpGlobalQuotaUsed -= Size; 00289 } 00290 00291 00292 VOID 00293 CmpComputeGlobalQuotaAllowed( 00294 VOID 00295 ) 00296 00297 /*++ 00298 00299 Routine Description: 00300 00301 Compute CmpGlobalQuota based on: 00302 (a) Size of paged pool 00303 (b) Explicit user registry commands to set registry GQ 00304 00305 Return Value: 00306 00307 NONE. 00308 00309 --*/ 00310 00311 { 00312 ULONG PagedLimit; 00313 00314 PagedLimit = CM_LIMIT_RATIO(MmSizeOfPagedPoolInBytes); 00315 00316 if ((CmRegistrySizeLimitLength != 4) || 00317 (CmRegistrySizeLimitType != REG_DWORD) || 00318 (CmRegistrySizeLimit == 0)) 00319 { 00320 // 00321 // If no value at all, or value of wrong type, or set to 00322 // zero, use internally computed default 00323 // 00324 CmpGlobalQuota = MmSizeOfPagedPoolInBytes / CM_DEFAULT_RATIO; 00325 00326 } else if (CmRegistrySizeLimit >= PagedLimit) { 00327 // 00328 // If more than computed upper bound, use computed upper bound 00329 // 00330 CmpGlobalQuota = PagedLimit; 00331 00332 } else { 00333 // 00334 // Use the set size 00335 // 00336 CmpGlobalQuota = CmRegistrySizeLimit; 00337 00338 } 00339 00340 if (CmpGlobalQuota > CM_WRAP_LIMIT) { 00341 CmpGlobalQuota = CM_WRAP_LIMIT; 00342 } 00343 if (CmpGlobalQuota < CM_MINIMUM_GLOBAL_QUOTA) { 00344 CmpGlobalQuota = CM_MINIMUM_GLOBAL_QUOTA; 00345 } 00346 00347 CmpGlobalQuotaWarning = CM_REGISTRY_WARNING_LEVEL * (CmpGlobalQuota / 100); 00348 00349 return; 00350 } 00351 00352 00353 VOID 00354 CmpSetGlobalQuotaAllowed( 00355 VOID 00356 ) 00357 /*++ 00358 00359 Routine Description: 00360 00361 Enables registry quota 00362 00363 NOTE: Do NOT put this in init segment, we call it after 00364 that code has been freed! 00365 00366 Return Value: 00367 00368 NONE. 00369 00370 --*/ 00371 { 00372 CmpGlobalQuotaAllowed = CmpGlobalQuota; 00373 }

Generated on Sat May 15 19:39:27 2004 for test by doxygen 1.3.7