Home | History | Annotate | Download | only in nfs
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * nnodes: vnode-like entities suited to NFS tasks
     28  *
     29  * Previous NFS server implementations have used vnodes exclusively for
     30  * performing client operations against a server file system. With pNFS
     31  * (Parallel NFS), it is required to have drastically different
     32  * implementations behind the NFS protocol operations. nnodes provide the
     33  * needed abstraction.
     34  *
     35  * Like vnodes, nnodes encapsulate a file or file-like object, and provide
     36  * a set of operations that can be performed on the object. Unlike vnodes,
     37  * the operations available on nnodes are made especially for implementing
     38  * an NFS server. The operations fall into three categories: data,
     39  * metadata, and state. Metadata operations include operations on the name
     40  * space, and state operations include such things as opening or locking a
     41  * file.
     42  *
     43  * The implementations hidden behind nnodes include the traditional vnode
     44  * API, the DMU API provided by ZFS, and proxy i/o performed by one node
     45  * of a pNFS server community against another. Of course, other future
     46  * implementations will also likely be provided.
     47  *
     48  * The usual scenario for an NFS implementation is to look up an
     49  * exportinfo with a filehandle, then to look up an nnode from the
     50  * exportinfo and the filehandle. The nnode is held via a reference count.
     51  * The nnode is used to perform what is needed to satisfy the client
     52  * request. When the request is complete, the nnode is released via
     53  * nnode_rele().
     54  *
     55  * NB: nnodes are currently kept in a global cache, but eventually there
     56  * will be one nnode cache per exportinfo structure.
     57  *
     58  * An nnode with a reference count of zero is subject to garbage
     59  * collection. The time that an nnode was last accessed is kept in the
     60  * nnode. When its last access is sufficiently far in the past, the
     61  * garbage collector will free the nnode with nnode_free().  When a system
     62  * is under memory pressure, the nnode may be freed more aggressively.
     63  * Other implementations of garbage collection are possible, e.g. a
     64  * generational garbage collector could be implemented at some future
     65  * time.
     66  *
     67  * The following API is project private.
     68  *
     69  * nnode lifecycle:
     70  *
     71  * nnode_from_fh_v3()
     72  * nnode_from_fh_v4()
     73  * nnode_from_fh_v41()
     74  * nnode_from_fh_ds(): These functions all return a held nnode based
     75  * upon the filehandle they are given.
     76  *
     77  * nnode_rele(): release the reference on the given nnode.
     78  *
     79  * nnode operations:
     80  *
     81  * data:
     82  *
     83  * All operations in this section nnode_error_t, which is a superset of a
     84  * standard errno.  A caller may use nnode_stat4() or nnode_stat3() to
     85  * convert it to an nfsstat4 or nfsstat3.
     86  *
     87  * nnop_io_prep(): prepare to do i/o.  Ensure that the caller has
     88  * permission to do the i/o.  Check if an operation is happening past the
     89  * current end-of-file.  Enforce mandatory locking, etc.
     90  *
     91  * nnop_read(): read
     92  *
     93  * nnop_write(): write
     94  *
     95  * nnop_io_release(): called after read or write.  It undoes any locks or
     96  * state changes that may have occured in nnode_io_prep().
     97  *
     98  * nnop_post_op_attr(): called by NFSv3 to return the post-op attribute.
     99  *
    100  * nnop_wcc_data_err(): called by NFSv3 to set the wcc_data in the return
    101  * code.
    102  *
    103  * nnop_io_getvp(): return the backing vnode, if any.  This operation will
    104  * be removed at a later time.
    105  *
    106  * metadata:
    107  *
    108  * state:
    109  *
    110  * nnop_check_stateid(): check the validity of a given stateid.
    111  */
    112 
    113 #ifndef _NNODE_H
    114 #define	_NNODE_H
    115 
    116 #ifdef _KERNEL
    117 #include <nfs/nfs4_kprot.h>
    118 #else
    119 #include <rpcsvc/nfs4_prot.h>
    120 #endif
    121 
    122 #include <nfs/nfs.h>
    123 #include <sys/types.h>
    124 
    125 #ifdef	__cplusplus
    126 extern "C" {
    127 #endif
    128 
    129 /* boilerplate */
    130 
    131 void nnode_mod_init(void);
    132 
    133 /* forward declarations */
    134 
    135 struct compound_state;
    136 struct mds_ds_fh;
    137 
    138 /* nnodes and their operations */
    139 
    140 typedef struct nnode nnode_t;
    141 
    142 /*
    143  * Error Reporting
    144  *
    145  * Generally, most nnode ops return errno values.  That keeps them more
    146  * protocol neutral.  However, there are some times when NFSv4 behaves
    147  * differently than v3; for example, when dealing with mandatory locks.
    148  *
    149  * The NNODE_ERROR_SPEC flag indicates that the value is not an errno, but
    150  * is instead an nnode specific error.  NNODE_ERROR_SPEC must not be set
    151  * in any valid errno values.
    152  */
    153 
    154 #define	NNODE_ERROR_SPEC	0x40000000
    155 typedef enum {
    156 	NNODE_ERROR_NOTIMPL = NNODE_ERROR_SPEC | 1,
    157 	NNODE_ERROR_LOCK,
    158 	NNODE_ERROR_IODIR,
    159 	NNODE_ERROR_AGAIN,
    160 	NNODE_ERROR_BADFH
    161 } nnode_error_t;
    162 
    163 nfsstat4 nnode_stat4(int, uint32_t);
    164 nfsstat3 nnode_stat3(int);
    165 
    166 typedef uint32_t nnode_io_flags_t;
    167 #define	NNODE_IO_FLAG_WRITE	0x01
    168 #define	NNODE_IO_FLAG_IN_CRIT	0x02
    169 #define	NNODE_IO_FLAG_RWLOCK	0x04
    170 #define	NNODE_IO_FLAG_EOF	0x08
    171 #define	NNODE_IO_FLAG_PAST_EOF	0x10
    172 #define	NNODE_IO_REMOVE_OBJ	0x20
    173 
    174 nnode_error_t nnop_io_prep(nnode_t *, nnode_io_flags_t *, cred_t *,
    175     caller_context_t *, offset_t, size_t, bslabel_t *);
    176 nnode_error_t nnop_read(nnode_t *, nnode_io_flags_t *, cred_t *,
    177     caller_context_t *, uio_t *, int);
    178 nnode_error_t nnop_write(nnode_t *, nnode_io_flags_t *, uio_t *, int, cred_t *,
    179     caller_context_t *, wcc_data *);
    180 void nnop_update(nnode_t *, nnode_io_flags_t, cred_t *, caller_context_t *,
    181     off64_t);
    182 nnode_error_t nnop_remove_obj(nnode_t *);
    183 void nnop_io_release(nnode_t *, nnode_io_flags_t, caller_context_t *);
    184 void nnop_post_op_attr(nnode_t *, post_op_attr *);
    185 void nnop_wcc_data_err(nnode_t *, wcc_data *);
    186 vnode_t *nnop_io_getvp(nnode_t *);
    187 
    188 vnode_t *nnop_md_getvp(nnode_t *);
    189 
    190 nfsstat4 nnop_check_stateid(nnode_t *, struct compound_state *, int, stateid4 *,
    191     bool_t, bool_t *, bool_t, caller_context_t *, clientid4 *);
    192 
    193 /* creating implementations of nnodes */
    194 
    195 typedef struct {
    196 	int (*ndo_io_prep)(void *, nnode_io_flags_t *, cred_t *,
    197 	    caller_context_t *, offset_t off, size_t, bslabel_t *);
    198 	int (*ndo_read)(void *, nnode_io_flags_t *, cred_t *,
    199 	    caller_context_t *, uio_t *, int);
    200 	int (*ndo_write)(void *, nnode_io_flags_t *, uio_t *, int, cred_t *,
    201 	    caller_context_t *, wcc_data *);
    202 	int (*ndo_remove_obj)(void *);
    203 	void (*ndo_update)(void *, nnode_io_flags_t, cred_t *,
    204 	    caller_context_t *, off64_t);
    205 	void (*ndo_io_release)(void *, nnode_io_flags_t, caller_context_t *);
    206 	void (*ndo_post_op_attr)(void *, post_op_attr *);
    207 	void (*ndo_wcc_data_err)(void *, wcc_data *);
    208 	vnode_t *(*ndo_getvp)(void *);
    209 	void (*ndo_free)(void *);
    210 } nnode_data_ops_t;
    211 
    212 typedef struct {
    213 	vnode_t *(*nmo_getvp)(void *);
    214 	void	(*nmo_free)(void *);
    215 } nnode_metadata_ops_t;
    216 
    217 typedef struct {
    218 	nfsstat4 (*nso_checkstate)(void *, struct compound_state *, int,
    219 	    stateid4 *, bool_t, bool_t *, bool_t,
    220 	    caller_context_t *, clientid4 *);
    221 	void	(*nso_free)(void *);
    222 } nnode_state_ops_t;
    223 
    224 typedef struct {
    225 	void *ns_key;
    226 	int (*ns_key_compare)(const void *, const void *);
    227 	void (*ns_key_free)(void *);
    228 
    229 	nnode_data_ops_t *ns_data_ops;
    230 	void *ns_data;
    231 
    232 	nnode_metadata_ops_t *ns_metadata_ops;
    233 	void *ns_metadata;
    234 
    235 	nnode_state_ops_t *ns_state_ops;
    236 	void *ns_state;
    237 } nnode_seed_t;
    238 
    239 /* getting nnodes from keys to be used */
    240 
    241 typedef struct {
    242 	void *nk_keydata;
    243 	int (*nk_compare)(const void *, const void *);
    244 } nnode_key_t;
    245 
    246 struct exportinfo;
    247 
    248 extern nnode_error_t (*nnode_from_fh_ds)(nnode_t **, struct mds_ds_fh *);
    249 nnode_error_t nnode_from_fh_v41(nnode_t **, nfs_fh4 *);
    250 nnode_error_t nnode_from_fh_v4(nnode_t **, nfs_fh4 *);
    251 nnode_error_t nnode_from_fh_v3(nnode_t **, nfs_fh3 *, struct exportinfo *);
    252 nnode_error_t nnode_from_vnode(nnode_t **, vnode_t *);
    253 void nnode_rele(nnode_t **);
    254 void nnode_free_export(struct exportinfo *);
    255 
    256 void nnode_mod_init(void);
    257 int nnode_mod_fini(void);
    258 void nnode_vn_init(void);
    259 void nnode_vn_fini(void);
    260 void nnode_proxy_init(void);
    261 void nnode_proxy_fini(void);
    262 
    263 /* nnode flag setting functions */
    264 
    265 int nnode_set_flag(nnode_t *, uint32_t);
    266 int nnode_clear_flag(nnode_t *, uint32_t);
    267 
    268 /* nnode flags */
    269 #define	NNODE_OBJ_REMOVE_IN_PROGRESS	0x01
    270 #define	NNODE_OBJ_REMOVED		0x02
    271 
    272 #define	NNODE_VALID_FLAG_BITS (\
    273     NNODE_OBJ_REMOVE_IN_PROGRESS | \
    274     NNODE_OBJ_REMOVED)
    275 
    276 /* nnode teardown function */
    277 int nnode_teardown_by_instance();
    278 
    279 /* nnode builders for specific implementations */
    280 
    281 typedef nnode_error_t (*nnode_init_function_t)(nnode_seed_t *, void *);
    282 int nnode_find_or_create(nnode_t **, nnode_key_t *, uint32_t, void *,
    283     nnode_init_function_t);
    284 
    285 #ifdef	__cplusplus
    286 }
    287 #endif
    288 
    289 #endif /* _NNODE_H */
    290