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/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30/*
31 * Portions of this source code were derived from Berkeley 4.3 BSD
32 * under license from the Regents of the University of California.
33 */
34
35#pragma ident	"%Z%%M%	%I%	%E% SMI"
36
37#include <sys/param.h>
38#include <sys/isa_defs.h>
39#include <sys/types.h>
40#include <sys/sysmacros.h>
41#include <sys/cred.h>
42#include <sys/systm.h>
43#include <sys/errno.h>
44#include <sys/pathname.h>
45#include <sys/vnode.h>
46#include <sys/vfs.h>
47#include <sys/file.h>
48#include <sys/uio.h>
49#include <sys/debug.h>
50#include <fs/fs_subr.h>
51
52/*
53 * Common code for pathconf(), fpathconf() system calls
54 */
55static long
56cpathconf(register vnode_t *vp, int cmd, struct cred *cr)
57{
58	struct statvfs64 sb;
59	int error;
60	ulong_t val;
61
62	switch (cmd) {
63	case _PC_2_SYMLINKS:
64		if (error = VOP_PATHCONF(vp, _PC_SYMLINK_MAX, &val, cr, NULL))
65			return ((long)set_errno(error));
66		return ((long)(val > 0));
67
68	case _PC_ALLOC_SIZE_MIN:
69	case _PC_REC_INCR_XFER_SIZE:
70	case _PC_REC_MAX_XFER_SIZE:
71	case _PC_REC_MIN_XFER_SIZE:
72	case _PC_REC_XFER_ALIGN:
73		if ((error = VFS_STATVFS(vp->v_vfsp, &sb)) != 0)
74			return ((long)set_errno(error));
75
76		/*
77		 * There is generally no harm in doing larger transfers, but
78		 * there's a point of diminishing returns.  With 1MB transfers,
79		 * even if they're random, you get very close to platter speed.
80		 * Se we return 1MB as the maximum transfer size.
81		 */
82		if (cmd == _PC_REC_MAX_XFER_SIZE)
83			return ((long)MAX(sb.f_bsize, 1UL << 20));
84
85		/*
86		 * By definition, f_frsize is the smallest filesystem block.
87		 * However, _PC_ALLOC_SIZE_MIN is intended to define the
88		 * threshold for direct I/O.  This implies two requirements:
89		 * the VM and I/O subsystems must be able to create mappings
90		 * for DMA, which requires at least page alignment; and the
91		 * filesystem must avoid read/modify/write, which generally
92		 * requires multiples of its 'preferred' blocksize, f_bsize.
93		 *
94		 * PAGESIZE alignment is sufficient for DMA and block copy.
95		 * Rounding up to the filesystem 'preferred' blocksize
96		 * works just as well.
97		 *
98		 * All together, this means that the remaining parameters
99		 * map into the same value.
100		 */
101		return ((long)MAX(sb.f_bsize, PAGESIZE));
102
103	case _PC_ASYNC_IO:
104		return (1l);
105
106	case _PC_PRIO_IO:
107		return ((long)set_errno(EINVAL));
108
109	case _PC_SYNC_IO:
110		if (!(error = VOP_FSYNC(vp, FSYNC, cr, NULL)))
111			return (1l);
112		return ((long)set_errno(error));
113
114	case _PC_XATTR_ENABLED:
115		return ((vp->v_vfsp->vfs_flag & VFS_XATTR) ? 1 : 0);
116
117	default:
118		if (error = VOP_PATHCONF(vp, cmd, &val, cr, NULL))
119			return ((long)set_errno(error));
120		return (val);
121	}
122	/* NOTREACHED */
123}
124
125/* fpathconf/pathconf interfaces */
126
127long
128fpathconf(int fdes, int name)
129{
130	file_t *fp;
131	long retval;
132
133	if ((fp = getf(fdes)) == NULL)
134		return (set_errno(EBADF));
135	retval = cpathconf(fp->f_vnode, name, fp->f_cred);
136	releasef(fdes);
137	return (retval);
138}
139
140long
141pathconf(char *fname, int name)
142{
143	vnode_t *vp;
144	long	retval;
145	int	error;
146	int 	estale_retry = 0;
147
148lookup:
149	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
150		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
151			goto lookup;
152		return ((long)set_errno(error));
153	}
154
155	retval = cpathconf(vp, name, CRED());
156	VN_RELE(vp);
157	return (retval);
158}
159