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 79static int 80cstatvfs32(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 142static int 143cstatvfs64(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 */ 162int 163statvfs(char *fname, struct statvfs *sbp) 164{ 165 vnode_t *vp; 166 int error; 167 int estale_retry = 0; 168 169lookup: 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 189int 190fstatvfs(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 */ 217int 218statvfs64(char *fname, struct statvfs64 *sbp) 219{ 220 vnode_t *vp; 221 int error; 222 int estale_retry = 0; 223 224lookup: 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 240int 241fstatvfs64(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 259static int 260cstatvfs64_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 */ 291int 292statvfs32(char *fname, struct statvfs32 *sbp) 293{ 294 vnode_t *vp; 295 int error; 296 int estale_retry = 0; 297 298lookup: 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 314int 315fstatvfs32(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 */ 332int 333statvfs64_32(char *fname, struct statvfs64_32 *sbp) 334{ 335 vnode_t *vp; 336 int error; 337 int estale_retry = 0; 338 339lookup: 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 355int 356fstatvfs64_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