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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <smbsrv/smb_incl.h> 29 #include <sys/sdt.h> 30 #include <sys/vfs.h> 31 #include <sys/vfs_opreg.h> 32 #include <sys/vnode.h> 33 #include <sys/fem.h> 34 35 int smb_fem_fcn_create(femarg_t *, char *, vattr_t *, vcexcl_t, int, 36 vnode_t **, cred_t *, int, caller_context_t *, vsecattr_t *); 37 int smb_fem_fcn_remove(femarg_t *, char *, cred_t *, 38 caller_context_t *, int); 39 int smb_fem_fcn_rename(femarg_t *, char *, vnode_t *, char *, 40 cred_t *, caller_context_t *, int); 41 int smb_fem_fcn_mkdir(femarg_t *, char *, vattr_t *, vnode_t **, 42 cred_t *, caller_context_t *, int, vsecattr_t *); 43 int smb_fem_fcn_rmdir(femarg_t *, char *, vnode_t *, cred_t *, 44 caller_context_t *, int); 45 int smb_fem_fcn_link(femarg_t *, vnode_t *, char *, cred_t *, 46 caller_context_t *, int); 47 int smb_fem_fcn_symlink(femarg_t *, char *, vattr_t *, 48 char *, cred_t *, caller_context_t *, int); 49 50 static const fs_operation_def_t smb_fcn_tmpl[] = { 51 VOPNAME_CREATE, { .femop_create = smb_fem_fcn_create }, 52 VOPNAME_REMOVE, {.femop_remove = smb_fem_fcn_remove}, 53 VOPNAME_RENAME, {.femop_rename = smb_fem_fcn_rename}, 54 VOPNAME_MKDIR, {.femop_mkdir = smb_fem_fcn_mkdir}, 55 VOPNAME_RMDIR, {.femop_rmdir = smb_fem_fcn_rmdir}, 56 VOPNAME_LINK, {.femop_link = smb_fem_fcn_link}, 57 VOPNAME_SYMLINK, {.femop_symlink = smb_fem_fcn_symlink}, 58 NULL, NULL 59 }; 60 61 static boolean_t smb_fem_initialized = B_FALSE; 62 static fem_t *smb_fcn_ops = NULL; 63 /* 64 * smb_fem_init 65 * 66 * This function is not multi-thread safe. The caller must make sure only one 67 * thread makes the call. 68 */ 69 int 70 smb_fem_init(void) 71 { 72 int rc = 0; 73 74 if (smb_fem_initialized) 75 return (0); 76 77 rc = fem_create("smb_fcn_ops", smb_fcn_tmpl, &smb_fcn_ops); 78 if (rc) 79 return (rc); 80 81 smb_fem_initialized = B_TRUE; 82 83 return (0); 84 } 85 86 /* 87 * smb_fem_fini 88 * 89 * This function is not multi-thread safe. The caller must make sure only one 90 * thread makes the call. 91 */ 92 void 93 smb_fem_fini(void) 94 { 95 if (!smb_fem_initialized) 96 return; 97 98 fem_free(smb_fcn_ops); 99 smb_fcn_ops = NULL; 100 smb_fem_initialized = B_FALSE; 101 } 102 103 void 104 smb_fem_fcn_install(smb_node_t *node) 105 { 106 (void) fem_install(node->vp, smb_fcn_ops, (void *)node, 107 OPARGUNIQ, (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release); 108 } 109 110 void 111 smb_fem_fcn_uninstall(smb_node_t *node) 112 { 113 (void) fem_uninstall(node->vp, smb_fcn_ops, (void *)node); 114 } 115 116 /* 117 * smb_fem_fcn_create() 118 * 119 * This monitor will catch only changes to VREG files and not to extended 120 * attribute files. This is fine because, for CIFS files, stream creates 121 * should not trigger any file change notification on the VDIR directory 122 * being monitored. Creates of any other kind of extended attribute in 123 * the directory will also not trigger any file change notification on the 124 * VDIR directory being monitored. 125 */ 126 127 int 128 smb_fem_fcn_create( 129 femarg_t *arg, 130 char *name, 131 vattr_t *vap, 132 vcexcl_t excl, 133 int mode, 134 vnode_t **vpp, 135 cred_t *cr, 136 int flag, 137 caller_context_t *ct, 138 vsecattr_t *vsecp) 139 { 140 smb_node_t *dnode; 141 int error; 142 143 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 144 145 ASSERT(dnode); 146 147 error = vnext_create(arg, name, vap, excl, mode, vpp, cr, flag, 148 ct, vsecp); 149 150 if (error == 0) 151 smb_process_node_notify_change_queue(dnode); 152 153 return (error); 154 } 155 156 /* 157 * smb_fem_fcn_remove() 158 * 159 * This monitor will catch only changes to VREG files and to not extended 160 * attribute files. This is fine because, for CIFS files, stream deletes 161 * should not trigger any file change notification on the VDIR directory 162 * being monitored. Deletes of any other kind of extended attribute in 163 * the directory will also not trigger any file change notification on the 164 * VDIR directory being monitored. 165 */ 166 167 int 168 smb_fem_fcn_remove( 169 femarg_t *arg, 170 char *name, 171 cred_t *cr, 172 caller_context_t *ct, 173 int flags) 174 { 175 smb_node_t *dnode; 176 int error; 177 178 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 179 180 ASSERT(dnode); 181 182 error = vnext_remove(arg, name, cr, ct, flags); 183 184 if (error == 0) 185 smb_process_node_notify_change_queue(dnode); 186 187 return (error); 188 } 189 190 int 191 smb_fem_fcn_rename( 192 femarg_t *arg, 193 char *snm, 194 vnode_t *tdvp, 195 char *tnm, 196 cred_t *cr, 197 caller_context_t *ct, 198 int flags) 199 { 200 smb_node_t *dnode; 201 int error; 202 203 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 204 205 ASSERT(dnode); 206 207 error = vnext_rename(arg, snm, tdvp, tnm, cr, ct, flags); 208 209 if (error == 0) 210 smb_process_node_notify_change_queue(dnode); 211 212 return (error); 213 } 214 215 int 216 smb_fem_fcn_mkdir( 217 femarg_t *arg, 218 char *name, 219 vattr_t *vap, 220 vnode_t **vpp, 221 cred_t *cr, 222 caller_context_t *ct, 223 int flags, 224 vsecattr_t *vsecp) 225 { 226 smb_node_t *dnode; 227 int error; 228 229 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 230 231 ASSERT(dnode); 232 233 error = vnext_mkdir(arg, name, vap, vpp, cr, ct, flags, vsecp); 234 235 if (error == 0) 236 smb_process_node_notify_change_queue(dnode); 237 238 return (error); 239 } 240 241 int 242 smb_fem_fcn_rmdir( 243 femarg_t *arg, 244 char *name, 245 vnode_t *cdir, 246 cred_t *cr, 247 caller_context_t *ct, 248 int flags) 249 { 250 smb_node_t *dnode; 251 int error; 252 253 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 254 255 ASSERT(dnode); 256 257 error = vnext_rmdir(arg, name, cdir, cr, ct, flags); 258 259 if (error == 0) 260 smb_process_node_notify_change_queue(dnode); 261 262 return (error); 263 } 264 265 int 266 smb_fem_fcn_link( 267 femarg_t *arg, 268 vnode_t *svp, 269 char *tnm, 270 cred_t *cr, 271 caller_context_t *ct, 272 int flags) 273 { 274 smb_node_t *dnode; 275 int error; 276 277 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 278 279 ASSERT(dnode); 280 281 error = vnext_link(arg, svp, tnm, cr, ct, flags); 282 283 if (error == 0) 284 smb_process_node_notify_change_queue(dnode); 285 286 return (error); 287 } 288 289 int 290 smb_fem_fcn_symlink( 291 femarg_t *arg, 292 char *linkname, 293 vattr_t *vap, 294 char *target, 295 cred_t *cr, 296 caller_context_t *ct, 297 int flags) 298 { 299 smb_node_t *dnode; 300 int error; 301 302 dnode = (smb_node_t *)arg->fa_fnode->fn_available; 303 304 ASSERT(dnode); 305 306 error = vnext_symlink(arg, linkname, vap, target, cr, ct, flags); 307 308 if (error == 0) 309 smb_process_node_notify_change_queue(dnode); 310 311 return (error); 312 } 313