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