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