2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * $Id: nfs_subr.c,v 1.3 1999/01/13 23:31:00 ezk Exp $
47 #endif /* HAVE_CONFIG_H */
52 * Convert from UN*X to NFS error code.
53 * Some systems like linux define their own (see
54 * conf/mount/mount_linux.h).
57 # define nfs_error(e) ((nfsstat)(e))
58 #endif /* nfs_error */
60 /* forward declarations */
61 static void count_map_entries(const am_node
*mp
, u_int
*out_blocks
, u_int
*out_bfree
, u_int
*out_bavail
);
65 do_readlink(am_node
*mp
, int *error_return
, nfsattrstat
**attrpp
)
70 * If there is a readlink method, then use
71 * that, otherwise if a link exists use
72 * that, otherwise use the mount point.
74 if (mp
->am_mnt
->mf_ops
->readlink
) {
76 mp
= (*mp
->am_mnt
->mf_ops
->readlink
) (mp
, &retry
);
78 *error_return
= retry
;
81 /* reschedule_timeout_mp(); */
87 ln
= mp
->am_mnt
->mf_mount
;
90 *attrpp
= &mp
->am_attr
;
97 nfsproc_null_2_svc(voidp argp
, struct svc_req
*rqstp
)
106 nfsproc_getattr_2_svc(am_nfs_fh
*argp
, struct svc_req
*rqstp
)
108 static nfsattrstat res
;
114 plog(XLOG_DEBUG
, "getattr:");
117 mp
= fh_to_mp2(argp
, &retry
);
122 plog(XLOG_DEBUG
, "\tretry=%d", retry
);
127 res
.ns_status
= nfs_error(retry
);
129 nfsattrstat
*attrp
= &mp
->am_attr
;
133 plog(XLOG_DEBUG
, "\tstat(%s), size = %d", mp
->am_path
,
134 (int) attrp
->ns_u
.ns_attr_u
.na_size
);
137 mp
->am_stats
.s_getattr
++;
141 #ifndef MNT2_NFS_OPT_SYMTTL
143 * This code is needed to defeat Solaris 2.4's (and newer) symlink values
144 * cache. It forces the last-modified time of the symlink to be current.
145 * It is not needed if the O/S has an nfs flag to turn off the
146 * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
148 if (++res
.ns_u
.ns_attr_u
.na_mtime
.nt_useconds
== 0)
149 ++res
.ns_u
.ns_attr_u
.na_mtime
.nt_seconds
;
150 #endif /* not MNT2_NFS_OPT_SYMTTL */
157 nfsproc_setattr_2_svc(nfssattrargs
*argp
, struct svc_req
*rqstp
)
159 static nfsattrstat res
;
161 if (!fh_to_mp(&argp
->sag_fhandle
))
162 res
.ns_status
= nfs_error(ESTALE
);
164 res
.ns_status
= nfs_error(EROFS
);
171 nfsproc_root_2_svc(voidp argp
, struct svc_req
*rqstp
)
180 nfsproc_lookup_2_svc(nfsdiropargs
*argp
, struct svc_req
*rqstp
)
182 static nfsdiropres res
;
188 plog(XLOG_DEBUG
, "lookup:");
191 mp
= fh_to_mp2(&argp
->da_fhandle
, &retry
);
195 res
.dr_status
= nfs_error(retry
);
201 plog(XLOG_DEBUG
, "\tlookuppn(%s, %s)", mp
->am_path
, argp
->da_name
);
203 ap
= (*mp
->am_mnt
->mf_ops
->lookuppn
) (mp
, argp
->da_name
, &error
, VLOOK_CREATE
);
207 dlog("Not sending RPC reply");
212 res
.dr_status
= nfs_error(error
);
215 * XXX: EXPERIMENTAL! Delay unmount of what was looked up. This
216 * should reduce the chance for race condition between unmounting an
217 * entry synchronously, and re-mounting it asynchronously.
219 if (ap
->am_ttl
< mp
->am_ttl
)
220 ap
->am_ttl
= mp
->am_ttl
;
221 mp_to_fh(ap
, &res
.dr_u
.dr_drok_u
.drok_fhandle
);
222 res
.dr_u
.dr_drok_u
.drok_attributes
= ap
->am_fattr
;
223 res
.dr_status
= NFS_OK
;
225 mp
->am_stats
.s_lookup
++;
226 /* reschedule_timeout_mp(); */
234 quick_reply(am_node
*mp
, int error
)
236 SVCXPRT
*transp
= mp
->am_transp
;
238 xdrproc_t xdr_result
= (xdrproc_t
) xdr_diropres
;
241 * If there's a transp structure then we can reply to the client's
242 * nfs lookup request.
247 * Construct a valid reply to a lookup request. Same
248 * code as in nfsproc_lookup_2_svc() above.
250 mp_to_fh(mp
, &res
.dr_u
.dr_drok_u
.drok_fhandle
);
251 res
.dr_u
.dr_drok_u
.drok_attributes
= mp
->am_fattr
;
252 res
.dr_status
= NFS_OK
;
255 * Return the error that was passed to us.
257 res
.dr_status
= nfs_error(error
);
262 if (!svc_sendreply(transp
, (XDRPROC_T_TYPE
) xdr_result
, (SVC_IN_ARG_TYPE
) & res
))
263 svcerr_systemerr(transp
);
266 * Free up transp. It's only used for one reply.
269 mp
->am_transp
= NULL
;
271 dlog("Quick reply sent for %s", mp
->am_mnt
->mf_mount
);
278 nfsproc_readlink_2_svc(am_nfs_fh
*argp
, struct svc_req
*rqstp
)
280 static nfsreadlinkres res
;
286 plog(XLOG_DEBUG
, "readlink:");
289 mp
= fh_to_mp2(argp
, &retry
);
294 res
.rlr_status
= nfs_error(retry
);
296 char *ln
= do_readlink(mp
, &retry
, (nfsattrstat
**) 0);
299 res
.rlr_status
= NFS_OK
;
303 plog(XLOG_DEBUG
, "\treadlink(%s) = %s", mp
->am_path
, ln
);
305 res
.rlr_u
.rlr_data_u
= ln
;
306 mp
->am_stats
.s_readlink
++;
314 nfsproc_read_2_svc(nfsreadargs
*argp
, struct svc_req
*rqstp
)
316 static nfsreadres res
;
318 memset((char *) &res
, 0, sizeof(res
));
319 res
.rr_status
= nfs_error(EACCES
);
326 nfsproc_writecache_2_svc(voidp argp
, struct svc_req
*rqstp
)
335 nfsproc_write_2_svc(nfswriteargs
*argp
, struct svc_req
*rqstp
)
337 static nfsattrstat res
;
339 if (!fh_to_mp(&argp
->wra_fhandle
))
340 res
.ns_status
= nfs_error(ESTALE
);
342 res
.ns_status
= nfs_error(EROFS
);
349 nfsproc_create_2_svc(nfscreateargs
*argp
, struct svc_req
*rqstp
)
351 static nfsdiropres res
;
353 if (!fh_to_mp(&argp
->ca_where
.da_fhandle
))
354 res
.dr_status
= nfs_error(ESTALE
);
356 res
.dr_status
= nfs_error(EROFS
);
363 unlink_or_rmdir(nfsdiropargs
*argp
, struct svc_req
*rqstp
, int unlinkp
)
368 am_node
*mp
= fh_to_mp3(&argp
->da_fhandle
, &retry
, VLOOK_DELETE
);
372 res
= nfs_error(retry
);
376 if (mp
->am_fattr
.na_type
!= NFDIR
) {
377 res
= nfs_error(ENOTDIR
);
383 plog(XLOG_DEBUG
, "\tremove(%s, %s)", mp
->am_path
, argp
->da_name
);
386 mp
= (*mp
->am_mnt
->mf_ops
->lookuppn
) (mp
, argp
->da_name
, &retry
, VLOOK_DELETE
);
394 * Usual NFS workaround...
396 else if (retry
== ENOENT
)
398 res
= nfs_error(retry
);
400 forcibly_timeout_mp(mp
);
410 nfsproc_remove_2_svc(nfsdiropargs
*argp
, struct svc_req
*rqstp
)
412 return unlink_or_rmdir(argp
, rqstp
, TRUE
);
417 nfsproc_rename_2_svc(nfsrenameargs
*argp
, struct svc_req
*rqstp
)
421 if (!fh_to_mp(&argp
->rna_from
.da_fhandle
) || !fh_to_mp(&argp
->rna_to
.da_fhandle
))
422 res
= nfs_error(ESTALE
);
424 * If the kernel is doing clever things with referenced files
425 * then let it pretend...
427 else if (NSTREQ(argp
->rna_to
.da_name
, ".nfs", 4))
430 * otherwise a failure
433 res
= nfs_error(EROFS
);
440 nfsproc_link_2_svc(nfslinkargs
*argp
, struct svc_req
*rqstp
)
444 if (!fh_to_mp(&argp
->la_fhandle
) || !fh_to_mp(&argp
->la_to
.da_fhandle
))
445 res
= nfs_error(ESTALE
);
447 res
= nfs_error(EROFS
);
454 nfsproc_symlink_2_svc(nfssymlinkargs
*argp
, struct svc_req
*rqstp
)
458 if (!fh_to_mp(&argp
->sla_from
.da_fhandle
))
459 res
= nfs_error(ESTALE
);
461 res
= nfs_error(EROFS
);
468 nfsproc_mkdir_2_svc(nfscreateargs
*argp
, struct svc_req
*rqstp
)
470 static nfsdiropres res
;
472 if (!fh_to_mp(&argp
->ca_where
.da_fhandle
))
473 res
.dr_status
= nfs_error(ESTALE
);
475 res
.dr_status
= nfs_error(EROFS
);
482 nfsproc_rmdir_2_svc(nfsdiropargs
*argp
, struct svc_req
*rqstp
)
484 return unlink_or_rmdir(argp
, rqstp
, FALSE
);
489 nfsproc_readdir_2_svc(nfsreaddirargs
*argp
, struct svc_req
*rqstp
)
491 static nfsreaddirres res
;
492 static nfsentry e_res
[MAX_READDIR_ENTRIES
];
498 plog(XLOG_DEBUG
, "readdir:");
501 mp
= fh_to_mp2(&argp
->rda_fhandle
, &retry
);
505 res
.rdr_status
= nfs_error(retry
);
509 plog(XLOG_DEBUG
, "\treaddir(%s)", mp
->am_path
);
511 res
.rdr_status
= nfs_error((*mp
->am_mnt
->mf_ops
->readdir
)
512 (mp
, argp
->rda_cookie
,
513 &res
.rdr_u
.rdr_reply_u
, e_res
, argp
->rda_count
));
514 mp
->am_stats
.s_readdir
++;
522 nfsproc_statfs_2_svc(am_nfs_fh
*argp
, struct svc_req
*rqstp
)
524 static nfsstatfsres res
;
531 plog(XLOG_DEBUG
, "statfs:");
534 mp
= fh_to_mp2(argp
, &retry
);
538 res
.sfr_status
= nfs_error(retry
);
543 plog(XLOG_DEBUG
, "\tstat_fs(%s)", mp
->am_path
);
547 * just return faked up file system information
549 fp
= &res
.sfr_u
.sfr_reply_u
;
551 fp
->sfrok_tsize
= 1024;
552 fp
->sfrok_bsize
= 1024;
554 /* check if map is browsable and show_statfs_entries=yes */
555 if ((gopt
.flags
& CFM_SHOW_STATFS_ENTRIES
) &&
556 mp
->am_mnt
&& mp
->am_mnt
->mf_mopts
) {
557 mnt
.mnt_opts
= mp
->am_mnt
->mf_mopts
;
558 if (hasmntopt(&mnt
, "browsable")) {
559 count_map_entries(mp
,
565 fp
->sfrok_blocks
= 0; /* set to 1 if you don't want empty automounts */
567 fp
->sfrok_bavail
= 0;
570 res
.sfr_status
= NFS_OK
;
571 mp
->am_stats
.s_statfs
++;
579 * count how many total entries there are in a map, and how many
580 * of them are in use.
583 count_map_entries(const am_node
*mp
, u_int
*out_blocks
, u_int
*out_bfree
, u_int
*out_bavail
)
585 u_int blocks
, bfree
, bavail
, i
;
590 blocks
= bfree
= bavail
= 0;
596 mmp
= (mnt_map
*) mf
->mf_private
;
600 /* iterate over keys */
601 for (i
= 0; i
< NKVHASH
; i
++) {
602 for (k
= mmp
->kvhash
[i
]; k
; k
= k
->next
) {
607 * XXX: Need to count how many are actively in use and recompute
608 * bfree and bavail based on it.
614 *out_blocks
= blocks
;
616 *out_bavail
= bavail
;