1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #pragma ident "%Z%%M% %I% %E% SMI" 35 36 /* 37 * Get file system statistics (statvfs and fstatvfs). 38 */ 39 40 #include <sys/types.h> 41 #include <sys/inttypes.h> 42 #include <sys/t_lock.h> 43 #include <sys/param.h> 44 #include <sys/errno.h> 45 #include <sys/fstyp.h> 46 #include <sys/systm.h> 47 #include <sys/vfs.h> 48 #include <sys/statvfs.h> 49 #include <sys/vnode.h> 50 #include <sys/file.h> 51 #include <sys/cmn_err.h> 52 #include <sys/debug.h> 53 #include <sys/pathname.h> 54 55 #include <vm/page.h> 56 #include <fs/fs_subr.h> 57 58 #define STATVFSCOPY(dst, src) \ 59 (dst)->f_bsize = (src)->f_bsize; \ 60 (dst)->f_frsize = (src)->f_frsize; \ 61 (dst)->f_blocks = (src)->f_blocks; \ 62 (dst)->f_bfree = (src)->f_bfree; \ 63 (dst)->f_bavail = (src)->f_bavail; \ 64 (dst)->f_files = (src)->f_files; \ 65 (dst)->f_ffree = (src)->f_ffree; \ 66 (dst)->f_favail = (src)->f_favail; \ 67 (dst)->f_fsid = (src)->f_fsid; \ 68 bcopy((src)->f_basetype, (dst)->f_basetype, \ 69 sizeof ((dst)->f_basetype)); \ 70 (dst)->f_flag = (src)->f_flag; \ 71 (dst)->f_namemax = (src)->f_namemax; \ 72 bcopy((src)->f_fstr, (dst)->f_fstr, \ 73 sizeof ((dst)->f_fstr)) 74 75 /* 76 * Common routines for statvfs and fstatvfs. 77 */ 78 79 static int 80 cstatvfs32(struct vfs *vfsp, struct statvfs32 *ubp) 81 { 82 struct statvfs64 ds64; 83 struct statvfs32 ds32; 84 int error; 85 86 #if !defined(lint) 87 ASSERT32(sizeof (struct statvfs) == sizeof (struct statvfs32)); 88 ASSERT32(sizeof (struct statvfs64) == sizeof (struct statvfs64_32)); 89 #endif 90 91 bzero(&ds64, sizeof (ds64)); 92 if ((error = VFS_STATVFS(vfsp, &ds64)) != 0) 93 return (error); 94 95 /* 96 * VFS_STATVFS can return data that is incompatible with the space 97 * available the 32-bit statvfs structure. Check here to see if 98 * it will fit into the 32-bit structure, if not, return EOVERFLOW. 99 * 100 * The check for -1 is because some file systems return -1 in the 101 * fields that are irrelevant or nonessential, and we do not want 102 * to return EOVERFLOW for them. For example: df is expected to 103 * show -1 in the output for some of these fields on NFS mounted 104 * filesystems. 105 */ 106 if (ds64.f_files == (fsfilcnt64_t)-1) 107 ds64.f_files = UINT32_MAX; 108 if (ds64.f_ffree == (fsfilcnt64_t)-1) 109 ds64.f_ffree = UINT32_MAX; 110 if (ds64.f_favail == (fsfilcnt64_t)-1) 111 ds64.f_favail = UINT32_MAX; 112 if (ds64.f_bavail == (fsblkcnt64_t)-1) 113 ds64.f_bavail = UINT32_MAX; 114 if (ds64.f_bfree == (fsblkcnt64_t)-1) 115 ds64.f_bfree = UINT32_MAX; 116 117 if (ds64.f_blocks > UINT32_MAX || ds64.f_bfree > UINT32_MAX || 118 ds64.f_bavail > UINT32_MAX || ds64.f_files > UINT32_MAX || 119 ds64.f_ffree > UINT32_MAX || ds64.f_favail > UINT32_MAX) 120 return (EOVERFLOW); 121 #ifdef _LP64 122 /* 123 * On the 64-bit kernel, even these fields grow to 64-bit 124 * quantities in the statvfs64 structure. 125 */ 126 if (ds64.f_namemax == (ulong_t)-1l) 127 ds64.f_namemax = UINT32_MAX; 128 129 if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX || 130 ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX || 131 ds64.f_namemax > UINT32_MAX) 132 return (EOVERFLOW); 133 #endif 134 135 bzero(&ds32, sizeof (ds32)); 136 STATVFSCOPY(&ds32, &ds64); 137 if (copyout(&ds32, ubp, sizeof (ds32)) != 0) 138 return (EFAULT); 139 return (0); 140 } 141 142 static int 143 cstatvfs64(struct vfs *vfsp, struct statvfs64 *ubp) 144 { 145 struct statvfs64 ds64; 146 int error; 147 148 #if !defined(lint) 149 ASSERT64(sizeof (struct statvfs) == sizeof (struct statvfs64)); 150 #endif 151 bzero(&ds64, sizeof (ds64)); 152 if ((error = VFS_STATVFS(vfsp, &ds64)) != 0) 153 return (error); 154 if (copyout(&ds64, ubp, sizeof (ds64)) != 0) 155 return (EFAULT); 156 return (0); 157 } 158 159 /* 160 * Native system calls 161 */ 162 int 163 statvfs(char *fname, struct statvfs *sbp) 164 { 165 vnode_t *vp; 166 int error; 167 int estale_retry = 0; 168 169 lookup: 170 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) { 171 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 172 goto lookup; 173 return (set_errno(error)); 174 } 175 #ifdef _LP64 176 error = cstatvfs64(vp->v_vfsp, (struct statvfs64 *)sbp); 177 #else 178 error = cstatvfs32(vp->v_vfsp, (struct statvfs32 *)sbp); 179 #endif 180 VN_RELE(vp); 181 if (error) { 182 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 183 goto lookup; 184 return (set_errno(error)); 185 } 186 return (0); 187 } 188 189 int 190 fstatvfs(int fdes, struct statvfs *sbp) 191 { 192 struct file *fp; 193 int error; 194 195 if ((fp = getf(fdes)) == NULL) 196 return (set_errno(EBADF)); 197 #ifdef _LP64 198 error = cstatvfs64(fp->f_vnode->v_vfsp, (struct statvfs64 *)sbp); 199 #else 200 error = cstatvfs32(fp->f_vnode->v_vfsp, (struct statvfs32 *)sbp); 201 #endif 202 releasef(fdes); 203 if (error) 204 return (set_errno(error)); 205 return (0); 206 } 207 208 #if defined(_ILP32) 209 210 /* 211 * Large File system calls. 212 * 213 * (We deliberately don't have special "large file" system calls in the 214 * 64-bit kernel -- we just use the native versions, since they're just 215 * as functional.) 216 */ 217 int 218 statvfs64(char *fname, struct statvfs64 *sbp) 219 { 220 vnode_t *vp; 221 int error; 222 int estale_retry = 0; 223 224 lookup: 225 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) { 226 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 227 goto lookup; 228 return (set_errno(error)); 229 } 230 error = cstatvfs64(vp->v_vfsp, sbp); 231 VN_RELE(vp); 232 if (error) { 233 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 234 goto lookup; 235 return (set_errno(error)); 236 } 237 return (0); 238 } 239 240 int 241 fstatvfs64(int fdes, struct statvfs64 *sbp) 242 { 243 struct file *fp; 244 int error; 245 246 if ((fp = getf(fdes)) == NULL) 247 return (set_errno(EBADF)); 248 error = cstatvfs64(fp->f_vnode->v_vfsp, sbp); 249 releasef(fdes); 250 if (error) 251 return (set_errno(error)); 252 return (0); 253 } 254 255 #endif /* _ILP32 */ 256 257 #ifdef _SYSCALL32_IMPL 258 259 static int 260 cstatvfs64_32(struct vfs *vfsp, struct statvfs64_32 *ubp) 261 { 262 struct statvfs64 ds64; 263 struct statvfs64_32 ds64_32; 264 int error; 265 266 bzero(&ds64, sizeof (ds64)); 267 if ((error = VFS_STATVFS(vfsp, &ds64)) != 0) 268 return (error); 269 270 /* 271 * On the 64-bit kernel, even these fields grow to 64-bit 272 * quantities in the statvfs64 structure. 273 */ 274 if (ds64.f_namemax == (ulong_t)-1l) 275 ds64.f_namemax = UINT32_MAX; 276 277 if (ds64.f_bsize > UINT32_MAX || ds64.f_frsize > UINT32_MAX || 278 ds64.f_fsid > UINT32_MAX || ds64.f_flag > UINT32_MAX || 279 ds64.f_namemax > UINT32_MAX) 280 return (EOVERFLOW); 281 282 STATVFSCOPY(&ds64_32, &ds64); 283 if (copyout(&ds64_32, ubp, sizeof (ds64_32)) != 0) 284 return (EFAULT); 285 return (0); 286 } 287 288 /* 289 * ILP32 "small file" system calls on LP64 kernel 290 */ 291 int 292 statvfs32(char *fname, struct statvfs32 *sbp) 293 { 294 vnode_t *vp; 295 int error; 296 int estale_retry = 0; 297 298 lookup: 299 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) { 300 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 301 goto lookup; 302 return (set_errno(error)); 303 } 304 error = cstatvfs32(vp->v_vfsp, sbp); 305 VN_RELE(vp); 306 if (error) { 307 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 308 goto lookup; 309 return (set_errno(error)); 310 } 311 return (0); 312 } 313 314 int 315 fstatvfs32(int fdes, struct statvfs32 *sbp) 316 { 317 struct file *fp; 318 int error; 319 320 if ((fp = getf(fdes)) == NULL) 321 return (set_errno(EBADF)); 322 error = cstatvfs32(fp->f_vnode->v_vfsp, sbp); 323 releasef(fdes); 324 if (error) 325 return (set_errno(error)); 326 return (0); 327 } 328 329 /* 330 * ILP32 Large File system calls on LP64 kernel 331 */ 332 int 333 statvfs64_32(char *fname, struct statvfs64_32 *sbp) 334 { 335 vnode_t *vp; 336 int error; 337 int estale_retry = 0; 338 339 lookup: 340 if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) { 341 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 342 goto lookup; 343 return (set_errno(error)); 344 } 345 error = cstatvfs64_32(vp->v_vfsp, sbp); 346 VN_RELE(vp); 347 if (error) { 348 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 349 goto lookup; 350 return (set_errno(error)); 351 } 352 return (0); 353 } 354 355 int 356 fstatvfs64_32(int fdes, struct statvfs64_32 *sbp) 357 { 358 struct file *fp; 359 int error; 360 361 if ((fp = getf(fdes)) == NULL) 362 return (set_errno(EBADF)); 363 error = cstatvfs64_32(fp->f_vnode->v_vfsp, sbp); 364 releasef(fdes); 365 if (error) 366 return (set_errno(error)); 367 return (0); 368 } 369 370 #endif /* _SYSCALL32_IMPL */ 371