1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy /* 22eda14cbcSMatt Macy * Copyright (C) 2011 Lawrence Livermore National Security, LLC. 23eda14cbcSMatt Macy * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). 24eda14cbcSMatt Macy * LLNL-CODE-403049. 25eda14cbcSMatt Macy * Rewritten for Linux by: 26eda14cbcSMatt Macy * Rohan Puri <rohan.puri15@gmail.com> 27eda14cbcSMatt Macy * Brian Behlendorf <behlendorf1@llnl.gov> 28eda14cbcSMatt Macy */ 29eda14cbcSMatt Macy 30eda14cbcSMatt Macy #include <sys/zfs_znode.h> 31eda14cbcSMatt Macy #include <sys/zfs_vfsops.h> 32eda14cbcSMatt Macy #include <sys/zfs_vnops.h> 33eda14cbcSMatt Macy #include <sys/zfs_ctldir.h> 34eda14cbcSMatt Macy #include <sys/zpl.h> 351f1e2261SMartin Matuska #include <sys/dmu.h> 361f1e2261SMartin Matuska #include <sys/dsl_dataset.h> 371f1e2261SMartin Matuska #include <sys/zap.h> 38eda14cbcSMatt Macy 39eda14cbcSMatt Macy /* 40eda14cbcSMatt Macy * Common open routine. Disallow any write access. 41eda14cbcSMatt Macy */ 42eda14cbcSMatt Macy static int 43eda14cbcSMatt Macy zpl_common_open(struct inode *ip, struct file *filp) 44eda14cbcSMatt Macy { 45315ee00fSMartin Matuska if (blk_mode_is_open_write(filp->f_mode)) 46eda14cbcSMatt Macy return (-EACCES); 47eda14cbcSMatt Macy 48eda14cbcSMatt Macy return (generic_file_open(ip, filp)); 49eda14cbcSMatt Macy } 50eda14cbcSMatt Macy 51eda14cbcSMatt Macy /* 52eda14cbcSMatt Macy * Get root directory contents. 53eda14cbcSMatt Macy */ 54eda14cbcSMatt Macy static int 55*7a7741afSMartin Matuska zpl_root_iterate(struct file *filp, struct dir_context *ctx) 56eda14cbcSMatt Macy { 57eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp)); 58eda14cbcSMatt Macy int error = 0; 59eda14cbcSMatt Macy 60*7a7741afSMartin Matuska if (zfsvfs->z_show_ctldir == ZFS_SNAPDIR_DISABLED) { 61*7a7741afSMartin Matuska return (SET_ERROR(ENOENT)); 62*7a7741afSMartin Matuska } 63*7a7741afSMartin Matuska 64c7046f76SMartin Matuska if ((error = zpl_enter(zfsvfs, FTAG)) != 0) 65c7046f76SMartin Matuska return (error); 66eda14cbcSMatt Macy 67*7a7741afSMartin Matuska if (!dir_emit_dots(filp, ctx)) 68eda14cbcSMatt Macy goto out; 69eda14cbcSMatt Macy 70eda14cbcSMatt Macy if (ctx->pos == 2) { 71*7a7741afSMartin Matuska if (!dir_emit(ctx, ZFS_SNAPDIR_NAME, 72eda14cbcSMatt Macy strlen(ZFS_SNAPDIR_NAME), ZFSCTL_INO_SNAPDIR, DT_DIR)) 73eda14cbcSMatt Macy goto out; 74eda14cbcSMatt Macy 75eda14cbcSMatt Macy ctx->pos++; 76eda14cbcSMatt Macy } 77eda14cbcSMatt Macy 78eda14cbcSMatt Macy if (ctx->pos == 3) { 79*7a7741afSMartin Matuska if (!dir_emit(ctx, ZFS_SHAREDIR_NAME, 80eda14cbcSMatt Macy strlen(ZFS_SHAREDIR_NAME), ZFSCTL_INO_SHARES, DT_DIR)) 81eda14cbcSMatt Macy goto out; 82eda14cbcSMatt Macy 83eda14cbcSMatt Macy ctx->pos++; 84eda14cbcSMatt Macy } 85eda14cbcSMatt Macy out: 86c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 87eda14cbcSMatt Macy 88eda14cbcSMatt Macy return (error); 89eda14cbcSMatt Macy } 90eda14cbcSMatt Macy 91eda14cbcSMatt Macy /* 92eda14cbcSMatt Macy * Get root directory attributes. 93eda14cbcSMatt Macy */ 94eda14cbcSMatt Macy static int 95d411c1d6SMartin Matuska #ifdef HAVE_IDMAP_IOPS_GETATTR 96d411c1d6SMartin Matuska zpl_root_getattr_impl(struct mnt_idmap *user_ns, 97d411c1d6SMartin Matuska const struct path *path, struct kstat *stat, u32 request_mask, 98d411c1d6SMartin Matuska unsigned int query_flags) 99d411c1d6SMartin Matuska #elif defined(HAVE_USERNS_IOPS_GETATTR) 100f9693befSMartin Matuska zpl_root_getattr_impl(struct user_namespace *user_ns, 101f9693befSMartin Matuska const struct path *path, struct kstat *stat, u32 request_mask, 102f9693befSMartin Matuska unsigned int query_flags) 103f9693befSMartin Matuska #else 104eda14cbcSMatt Macy zpl_root_getattr_impl(const struct path *path, struct kstat *stat, 105eda14cbcSMatt Macy u32 request_mask, unsigned int query_flags) 106f9693befSMartin Matuska #endif 107eda14cbcSMatt Macy { 108c03c5b1cSMartin Matuska (void) request_mask, (void) query_flags; 109eda14cbcSMatt Macy struct inode *ip = path->dentry->d_inode; 110eda14cbcSMatt Macy 111d411c1d6SMartin Matuska #if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) 112c03c5b1cSMartin Matuska #ifdef HAVE_GENERIC_FILLATTR_USERNS 113f9693befSMartin Matuska generic_fillattr(user_ns, ip, stat); 114d411c1d6SMartin Matuska #elif defined(HAVE_GENERIC_FILLATTR_IDMAP) 115d411c1d6SMartin Matuska generic_fillattr(user_ns, ip, stat); 116abcdc1b9SMartin Matuska #elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK) 117abcdc1b9SMartin Matuska generic_fillattr(user_ns, request_mask, ip, stat); 118f9693befSMartin Matuska #else 119c03c5b1cSMartin Matuska (void) user_ns; 120c03c5b1cSMartin Matuska #endif 121c03c5b1cSMartin Matuska #else 122eda14cbcSMatt Macy generic_fillattr(ip, stat); 123f9693befSMartin Matuska #endif 124eda14cbcSMatt Macy stat->atime = current_time(ip); 125eda14cbcSMatt Macy 126eda14cbcSMatt Macy return (0); 127eda14cbcSMatt Macy } 128eda14cbcSMatt Macy ZPL_GETATTR_WRAPPER(zpl_root_getattr); 129eda14cbcSMatt Macy 130eda14cbcSMatt Macy static struct dentry * 131eda14cbcSMatt Macy zpl_root_lookup(struct inode *dip, struct dentry *dentry, unsigned int flags) 132eda14cbcSMatt Macy { 133eda14cbcSMatt Macy cred_t *cr = CRED(); 134eda14cbcSMatt Macy struct inode *ip; 135eda14cbcSMatt Macy int error; 136eda14cbcSMatt Macy 137eda14cbcSMatt Macy crhold(cr); 138eda14cbcSMatt Macy error = -zfsctl_root_lookup(dip, dname(dentry), &ip, 0, cr, NULL, NULL); 139eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 140eda14cbcSMatt Macy crfree(cr); 141eda14cbcSMatt Macy 142eda14cbcSMatt Macy if (error) { 143eda14cbcSMatt Macy if (error == -ENOENT) 144eda14cbcSMatt Macy return (d_splice_alias(NULL, dentry)); 145eda14cbcSMatt Macy else 146eda14cbcSMatt Macy return (ERR_PTR(error)); 147eda14cbcSMatt Macy } 148eda14cbcSMatt Macy 149eda14cbcSMatt Macy return (d_splice_alias(ip, dentry)); 150eda14cbcSMatt Macy } 151eda14cbcSMatt Macy 152eda14cbcSMatt Macy /* 153eda14cbcSMatt Macy * The '.zfs' control directory file and inode operations. 154eda14cbcSMatt Macy */ 155eda14cbcSMatt Macy const struct file_operations zpl_fops_root = { 156eda14cbcSMatt Macy .open = zpl_common_open, 157eda14cbcSMatt Macy .llseek = generic_file_llseek, 158eda14cbcSMatt Macy .read = generic_read_dir, 159eda14cbcSMatt Macy .iterate_shared = zpl_root_iterate, 160eda14cbcSMatt Macy }; 161eda14cbcSMatt Macy 162eda14cbcSMatt Macy const struct inode_operations zpl_ops_root = { 163eda14cbcSMatt Macy .lookup = zpl_root_lookup, 164eda14cbcSMatt Macy .getattr = zpl_root_getattr, 165eda14cbcSMatt Macy }; 166eda14cbcSMatt Macy 167eda14cbcSMatt Macy static struct vfsmount * 168eda14cbcSMatt Macy zpl_snapdir_automount(struct path *path) 169eda14cbcSMatt Macy { 170eda14cbcSMatt Macy int error; 171eda14cbcSMatt Macy 172eda14cbcSMatt Macy error = -zfsctl_snapshot_mount(path, 0); 173eda14cbcSMatt Macy if (error) 174eda14cbcSMatt Macy return (ERR_PTR(error)); 175eda14cbcSMatt Macy 176eda14cbcSMatt Macy /* 177eda14cbcSMatt Macy * Rather than returning the new vfsmount for the snapshot we must 178eda14cbcSMatt Macy * return NULL to indicate a mount collision. This is done because 179eda14cbcSMatt Macy * the user space mount calls do_add_mount() which adds the vfsmount 180eda14cbcSMatt Macy * to the name space. If we returned the new mount here it would be 181eda14cbcSMatt Macy * added again to the vfsmount list resulting in list corruption. 182eda14cbcSMatt Macy */ 183eda14cbcSMatt Macy return (NULL); 184eda14cbcSMatt Macy } 185eda14cbcSMatt Macy 186eda14cbcSMatt Macy /* 187eda14cbcSMatt Macy * Negative dentries must always be revalidated so newly created snapshots 188eda14cbcSMatt Macy * can be detected and automounted. Normal dentries should be kept because 189eda14cbcSMatt Macy * as of the 3.18 kernel revaliding the mountpoint dentry will result in 190eda14cbcSMatt Macy * the snapshot being immediately unmounted. 191eda14cbcSMatt Macy */ 192eda14cbcSMatt Macy static int 193eda14cbcSMatt Macy zpl_snapdir_revalidate(struct dentry *dentry, unsigned int flags) 194eda14cbcSMatt Macy { 195eda14cbcSMatt Macy return (!!dentry->d_inode); 196eda14cbcSMatt Macy } 197eda14cbcSMatt Macy 198be181ee2SMartin Matuska static dentry_operations_t zpl_dops_snapdirs = { 199eda14cbcSMatt Macy /* 200eda14cbcSMatt Macy * Auto mounting of snapshots is only supported for 2.6.37 and 201eda14cbcSMatt Macy * newer kernels. Prior to this kernel the ops->follow_link() 202eda14cbcSMatt Macy * callback was used as a hack to trigger the mount. The 203eda14cbcSMatt Macy * resulting vfsmount was then explicitly grafted in to the 204eda14cbcSMatt Macy * name space. While it might be possible to add compatibility 205eda14cbcSMatt Macy * code to accomplish this it would require considerable care. 206eda14cbcSMatt Macy */ 207eda14cbcSMatt Macy .d_automount = zpl_snapdir_automount, 208eda14cbcSMatt Macy .d_revalidate = zpl_snapdir_revalidate, 209eda14cbcSMatt Macy }; 210eda14cbcSMatt Macy 211eda14cbcSMatt Macy static struct dentry * 212eda14cbcSMatt Macy zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry, 213eda14cbcSMatt Macy unsigned int flags) 214eda14cbcSMatt Macy { 215eda14cbcSMatt Macy fstrans_cookie_t cookie; 216eda14cbcSMatt Macy cred_t *cr = CRED(); 217eda14cbcSMatt Macy struct inode *ip = NULL; 218eda14cbcSMatt Macy int error; 219eda14cbcSMatt Macy 220eda14cbcSMatt Macy crhold(cr); 221eda14cbcSMatt Macy cookie = spl_fstrans_mark(); 222eda14cbcSMatt Macy error = -zfsctl_snapdir_lookup(dip, dname(dentry), &ip, 223eda14cbcSMatt Macy 0, cr, NULL, NULL); 224eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 225eda14cbcSMatt Macy spl_fstrans_unmark(cookie); 226eda14cbcSMatt Macy crfree(cr); 227eda14cbcSMatt Macy 228eda14cbcSMatt Macy if (error && error != -ENOENT) 229eda14cbcSMatt Macy return (ERR_PTR(error)); 230eda14cbcSMatt Macy 231eda14cbcSMatt Macy ASSERT(error == 0 || ip == NULL); 232eda14cbcSMatt Macy d_clear_d_op(dentry); 233eda14cbcSMatt Macy d_set_d_op(dentry, &zpl_dops_snapdirs); 234eda14cbcSMatt Macy dentry->d_flags |= DCACHE_NEED_AUTOMOUNT; 235eda14cbcSMatt Macy 236eda14cbcSMatt Macy return (d_splice_alias(ip, dentry)); 237eda14cbcSMatt Macy } 238eda14cbcSMatt Macy 239eda14cbcSMatt Macy static int 240*7a7741afSMartin Matuska zpl_snapdir_iterate(struct file *filp, struct dir_context *ctx) 241eda14cbcSMatt Macy { 242eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp)); 243eda14cbcSMatt Macy fstrans_cookie_t cookie; 244eda14cbcSMatt Macy char snapname[MAXNAMELEN]; 245eda14cbcSMatt Macy boolean_t case_conflict; 246eda14cbcSMatt Macy uint64_t id, pos; 247eda14cbcSMatt Macy int error = 0; 248eda14cbcSMatt Macy 249c7046f76SMartin Matuska if ((error = zpl_enter(zfsvfs, FTAG)) != 0) 250c7046f76SMartin Matuska return (error); 251eda14cbcSMatt Macy cookie = spl_fstrans_mark(); 252eda14cbcSMatt Macy 253*7a7741afSMartin Matuska if (!dir_emit_dots(filp, ctx)) 254eda14cbcSMatt Macy goto out; 255eda14cbcSMatt Macy 2567877fdebSMatt Macy /* Start the position at 0 if it already emitted . and .. */ 2577877fdebSMatt Macy pos = (ctx->pos == 2 ? 0 : ctx->pos); 258eda14cbcSMatt Macy while (error == 0) { 259eda14cbcSMatt Macy dsl_pool_config_enter(dmu_objset_pool(zfsvfs->z_os), FTAG); 260eda14cbcSMatt Macy error = -dmu_snapshot_list_next(zfsvfs->z_os, MAXNAMELEN, 261eda14cbcSMatt Macy snapname, &id, &pos, &case_conflict); 262eda14cbcSMatt Macy dsl_pool_config_exit(dmu_objset_pool(zfsvfs->z_os), FTAG); 263eda14cbcSMatt Macy if (error) 264eda14cbcSMatt Macy goto out; 265eda14cbcSMatt Macy 266*7a7741afSMartin Matuska if (!dir_emit(ctx, snapname, strlen(snapname), 267eda14cbcSMatt Macy ZFSCTL_INO_SHARES - id, DT_DIR)) 268eda14cbcSMatt Macy goto out; 269eda14cbcSMatt Macy 270eda14cbcSMatt Macy ctx->pos = pos; 271eda14cbcSMatt Macy } 272eda14cbcSMatt Macy out: 273eda14cbcSMatt Macy spl_fstrans_unmark(cookie); 274c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 275eda14cbcSMatt Macy 276eda14cbcSMatt Macy if (error == -ENOENT) 277eda14cbcSMatt Macy return (0); 278eda14cbcSMatt Macy 279eda14cbcSMatt Macy return (error); 280eda14cbcSMatt Macy } 281eda14cbcSMatt Macy 282eda14cbcSMatt Macy static int 283f9693befSMartin Matuska #ifdef HAVE_IOPS_RENAME_USERNS 284f9693befSMartin Matuska zpl_snapdir_rename2(struct user_namespace *user_ns, struct inode *sdip, 285f9693befSMartin Matuska struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, 286f9693befSMartin Matuska unsigned int flags) 287d411c1d6SMartin Matuska #elif defined(HAVE_IOPS_RENAME_IDMAP) 288d411c1d6SMartin Matuska zpl_snapdir_rename2(struct mnt_idmap *user_ns, struct inode *sdip, 289d411c1d6SMartin Matuska struct dentry *sdentry, struct inode *tdip, struct dentry *tdentry, 290d411c1d6SMartin Matuska unsigned int flags) 291f9693befSMartin Matuska #else 292eda14cbcSMatt Macy zpl_snapdir_rename2(struct inode *sdip, struct dentry *sdentry, 293eda14cbcSMatt Macy struct inode *tdip, struct dentry *tdentry, unsigned int flags) 294f9693befSMartin Matuska #endif 295eda14cbcSMatt Macy { 296eda14cbcSMatt Macy cred_t *cr = CRED(); 297eda14cbcSMatt Macy int error; 298eda14cbcSMatt Macy 299eda14cbcSMatt Macy /* We probably don't want to support renameat2(2) in ctldir */ 300eda14cbcSMatt Macy if (flags) 301eda14cbcSMatt Macy return (-EINVAL); 302eda14cbcSMatt Macy 303eda14cbcSMatt Macy crhold(cr); 304eda14cbcSMatt Macy error = -zfsctl_snapdir_rename(sdip, dname(sdentry), 305eda14cbcSMatt Macy tdip, dname(tdentry), cr, 0); 306eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 307eda14cbcSMatt Macy crfree(cr); 308eda14cbcSMatt Macy 309eda14cbcSMatt Macy return (error); 310eda14cbcSMatt Macy } 311eda14cbcSMatt Macy 312d411c1d6SMartin Matuska #if (!defined(HAVE_RENAME_WANTS_FLAGS) && \ 313d411c1d6SMartin Matuska !defined(HAVE_IOPS_RENAME_USERNS) && \ 314d411c1d6SMartin Matuska !defined(HAVE_IOPS_RENAME_IDMAP)) 315eda14cbcSMatt Macy static int 316eda14cbcSMatt Macy zpl_snapdir_rename(struct inode *sdip, struct dentry *sdentry, 317eda14cbcSMatt Macy struct inode *tdip, struct dentry *tdentry) 318eda14cbcSMatt Macy { 319eda14cbcSMatt Macy return (zpl_snapdir_rename2(sdip, sdentry, tdip, tdentry, 0)); 320eda14cbcSMatt Macy } 321eda14cbcSMatt Macy #endif 322eda14cbcSMatt Macy 323eda14cbcSMatt Macy static int 324eda14cbcSMatt Macy zpl_snapdir_rmdir(struct inode *dip, struct dentry *dentry) 325eda14cbcSMatt Macy { 326eda14cbcSMatt Macy cred_t *cr = CRED(); 327eda14cbcSMatt Macy int error; 328eda14cbcSMatt Macy 329eda14cbcSMatt Macy crhold(cr); 330eda14cbcSMatt Macy error = -zfsctl_snapdir_remove(dip, dname(dentry), cr, 0); 331eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 332eda14cbcSMatt Macy crfree(cr); 333eda14cbcSMatt Macy 334eda14cbcSMatt Macy return (error); 335eda14cbcSMatt Macy } 336eda14cbcSMatt Macy 337eda14cbcSMatt Macy static int 338f9693befSMartin Matuska #ifdef HAVE_IOPS_MKDIR_USERNS 339f9693befSMartin Matuska zpl_snapdir_mkdir(struct user_namespace *user_ns, struct inode *dip, 340f9693befSMartin Matuska struct dentry *dentry, umode_t mode) 341d411c1d6SMartin Matuska #elif defined(HAVE_IOPS_MKDIR_IDMAP) 342d411c1d6SMartin Matuska zpl_snapdir_mkdir(struct mnt_idmap *user_ns, struct inode *dip, 343d411c1d6SMartin Matuska struct dentry *dentry, umode_t mode) 344f9693befSMartin Matuska #else 345eda14cbcSMatt Macy zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) 346f9693befSMartin Matuska #endif 347eda14cbcSMatt Macy { 348eda14cbcSMatt Macy cred_t *cr = CRED(); 349eda14cbcSMatt Macy vattr_t *vap; 350eda14cbcSMatt Macy struct inode *ip; 351eda14cbcSMatt Macy int error; 352eda14cbcSMatt Macy 353eda14cbcSMatt Macy crhold(cr); 354eda14cbcSMatt Macy vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); 355d411c1d6SMartin Matuska #if (defined(HAVE_IOPS_MKDIR_USERNS) || defined(HAVE_IOPS_MKDIR_IDMAP)) 356dbd5678dSMartin Matuska zpl_vap_init(vap, dip, mode | S_IFDIR, cr, user_ns); 357dbd5678dSMartin Matuska #else 358d411c1d6SMartin Matuska zpl_vap_init(vap, dip, mode | S_IFDIR, cr, zfs_init_idmap); 359dbd5678dSMartin Matuska #endif 360eda14cbcSMatt Macy 361eda14cbcSMatt Macy error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0); 362eda14cbcSMatt Macy if (error == 0) { 363eda14cbcSMatt Macy d_clear_d_op(dentry); 364eda14cbcSMatt Macy d_set_d_op(dentry, &zpl_dops_snapdirs); 365eda14cbcSMatt Macy d_instantiate(dentry, ip); 366eda14cbcSMatt Macy } 367eda14cbcSMatt Macy 368eda14cbcSMatt Macy kmem_free(vap, sizeof (vattr_t)); 369eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 370eda14cbcSMatt Macy crfree(cr); 371eda14cbcSMatt Macy 372eda14cbcSMatt Macy return (error); 373eda14cbcSMatt Macy } 374eda14cbcSMatt Macy 375eda14cbcSMatt Macy /* 376eda14cbcSMatt Macy * Get snapshot directory attributes. 377eda14cbcSMatt Macy */ 378eda14cbcSMatt Macy static int 379d411c1d6SMartin Matuska #ifdef HAVE_IDMAP_IOPS_GETATTR 380d411c1d6SMartin Matuska zpl_snapdir_getattr_impl(struct mnt_idmap *user_ns, 381d411c1d6SMartin Matuska const struct path *path, struct kstat *stat, u32 request_mask, 382d411c1d6SMartin Matuska unsigned int query_flags) 383d411c1d6SMartin Matuska #elif defined(HAVE_USERNS_IOPS_GETATTR) 384f9693befSMartin Matuska zpl_snapdir_getattr_impl(struct user_namespace *user_ns, 385f9693befSMartin Matuska const struct path *path, struct kstat *stat, u32 request_mask, 386f9693befSMartin Matuska unsigned int query_flags) 387f9693befSMartin Matuska #else 388eda14cbcSMatt Macy zpl_snapdir_getattr_impl(const struct path *path, struct kstat *stat, 389eda14cbcSMatt Macy u32 request_mask, unsigned int query_flags) 390f9693befSMartin Matuska #endif 391eda14cbcSMatt Macy { 392c03c5b1cSMartin Matuska (void) request_mask, (void) query_flags; 393eda14cbcSMatt Macy struct inode *ip = path->dentry->d_inode; 394eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ITOZSB(ip); 395c7046f76SMartin Matuska int error; 396eda14cbcSMatt Macy 397c7046f76SMartin Matuska if ((error = zpl_enter(zfsvfs, FTAG)) != 0) 398c7046f76SMartin Matuska return (error); 399d411c1d6SMartin Matuska #if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) 400c03c5b1cSMartin Matuska #ifdef HAVE_GENERIC_FILLATTR_USERNS 401f9693befSMartin Matuska generic_fillattr(user_ns, ip, stat); 402d411c1d6SMartin Matuska #elif defined(HAVE_GENERIC_FILLATTR_IDMAP) 403d411c1d6SMartin Matuska generic_fillattr(user_ns, ip, stat); 404abcdc1b9SMartin Matuska #elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK) 405abcdc1b9SMartin Matuska generic_fillattr(user_ns, request_mask, ip, stat); 406f9693befSMartin Matuska #else 407c03c5b1cSMartin Matuska (void) user_ns; 408c03c5b1cSMartin Matuska #endif 409c03c5b1cSMartin Matuska #else 410eda14cbcSMatt Macy generic_fillattr(ip, stat); 411f9693befSMartin Matuska #endif 412eda14cbcSMatt Macy 413eda14cbcSMatt Macy stat->nlink = stat->size = 2; 4141f1e2261SMartin Matuska 4151f1e2261SMartin Matuska dsl_dataset_t *ds = dmu_objset_ds(zfsvfs->z_os); 4161f1e2261SMartin Matuska if (dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0) { 4171f1e2261SMartin Matuska uint64_t snap_count; 4181f1e2261SMartin Matuska int err = zap_count( 4191f1e2261SMartin Matuska dmu_objset_pool(ds->ds_objset)->dp_meta_objset, 4201f1e2261SMartin Matuska dsl_dataset_phys(ds)->ds_snapnames_zapobj, &snap_count); 4211f1e2261SMartin Matuska if (err != 0) { 422c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 4231f1e2261SMartin Matuska return (-err); 4241f1e2261SMartin Matuska } 4251f1e2261SMartin Matuska stat->nlink += snap_count; 4261f1e2261SMartin Matuska } 4271f1e2261SMartin Matuska 428eda14cbcSMatt Macy stat->ctime = stat->mtime = dmu_objset_snap_cmtime(zfsvfs->z_os); 429eda14cbcSMatt Macy stat->atime = current_time(ip); 430c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 431eda14cbcSMatt Macy 432eda14cbcSMatt Macy return (0); 433eda14cbcSMatt Macy } 434eda14cbcSMatt Macy ZPL_GETATTR_WRAPPER(zpl_snapdir_getattr); 435eda14cbcSMatt Macy 436eda14cbcSMatt Macy /* 437eda14cbcSMatt Macy * The '.zfs/snapshot' directory file operations. These mainly control 438eda14cbcSMatt Macy * generating the list of available snapshots when doing an 'ls' in the 439eda14cbcSMatt Macy * directory. See zpl_snapdir_readdir(). 440eda14cbcSMatt Macy */ 441eda14cbcSMatt Macy const struct file_operations zpl_fops_snapdir = { 442eda14cbcSMatt Macy .open = zpl_common_open, 443eda14cbcSMatt Macy .llseek = generic_file_llseek, 444eda14cbcSMatt Macy .read = generic_read_dir, 445eda14cbcSMatt Macy .iterate_shared = zpl_snapdir_iterate, 446eda14cbcSMatt Macy 447eda14cbcSMatt Macy }; 448eda14cbcSMatt Macy 449eda14cbcSMatt Macy /* 450eda14cbcSMatt Macy * The '.zfs/snapshot' directory inode operations. These mainly control 451eda14cbcSMatt Macy * creating an inode for a snapshot directory and initializing the needed 452eda14cbcSMatt Macy * infrastructure to automount the snapshot. See zpl_snapdir_lookup(). 453eda14cbcSMatt Macy */ 454eda14cbcSMatt Macy const struct inode_operations zpl_ops_snapdir = { 455eda14cbcSMatt Macy .lookup = zpl_snapdir_lookup, 456eda14cbcSMatt Macy .getattr = zpl_snapdir_getattr, 457d411c1d6SMartin Matuska #if (defined(HAVE_RENAME_WANTS_FLAGS) || \ 458d411c1d6SMartin Matuska defined(HAVE_IOPS_RENAME_USERNS) || \ 459d411c1d6SMartin Matuska defined(HAVE_IOPS_RENAME_IDMAP)) 460eda14cbcSMatt Macy .rename = zpl_snapdir_rename2, 461eda14cbcSMatt Macy #else 462eda14cbcSMatt Macy .rename = zpl_snapdir_rename, 463eda14cbcSMatt Macy #endif 464eda14cbcSMatt Macy .rmdir = zpl_snapdir_rmdir, 465eda14cbcSMatt Macy .mkdir = zpl_snapdir_mkdir, 466eda14cbcSMatt Macy }; 467eda14cbcSMatt Macy 468eda14cbcSMatt Macy static struct dentry * 469eda14cbcSMatt Macy zpl_shares_lookup(struct inode *dip, struct dentry *dentry, 470eda14cbcSMatt Macy unsigned int flags) 471eda14cbcSMatt Macy { 472eda14cbcSMatt Macy fstrans_cookie_t cookie; 473eda14cbcSMatt Macy cred_t *cr = CRED(); 474eda14cbcSMatt Macy struct inode *ip = NULL; 475eda14cbcSMatt Macy int error; 476eda14cbcSMatt Macy 477eda14cbcSMatt Macy crhold(cr); 478eda14cbcSMatt Macy cookie = spl_fstrans_mark(); 479eda14cbcSMatt Macy error = -zfsctl_shares_lookup(dip, dname(dentry), &ip, 480eda14cbcSMatt Macy 0, cr, NULL, NULL); 481eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 482eda14cbcSMatt Macy spl_fstrans_unmark(cookie); 483eda14cbcSMatt Macy crfree(cr); 484eda14cbcSMatt Macy 485eda14cbcSMatt Macy if (error) { 486eda14cbcSMatt Macy if (error == -ENOENT) 487eda14cbcSMatt Macy return (d_splice_alias(NULL, dentry)); 488eda14cbcSMatt Macy else 489eda14cbcSMatt Macy return (ERR_PTR(error)); 490eda14cbcSMatt Macy } 491eda14cbcSMatt Macy 492eda14cbcSMatt Macy return (d_splice_alias(ip, dentry)); 493eda14cbcSMatt Macy } 494eda14cbcSMatt Macy 495eda14cbcSMatt Macy static int 496*7a7741afSMartin Matuska zpl_shares_iterate(struct file *filp, struct dir_context *ctx) 497eda14cbcSMatt Macy { 498eda14cbcSMatt Macy fstrans_cookie_t cookie; 499eda14cbcSMatt Macy cred_t *cr = CRED(); 500eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ITOZSB(file_inode(filp)); 501eda14cbcSMatt Macy znode_t *dzp; 502eda14cbcSMatt Macy int error = 0; 503eda14cbcSMatt Macy 504c7046f76SMartin Matuska if ((error = zpl_enter(zfsvfs, FTAG)) != 0) 505c7046f76SMartin Matuska return (error); 506eda14cbcSMatt Macy cookie = spl_fstrans_mark(); 507eda14cbcSMatt Macy 508eda14cbcSMatt Macy if (zfsvfs->z_shares_dir == 0) { 509*7a7741afSMartin Matuska dir_emit_dots(filp, ctx); 510eda14cbcSMatt Macy goto out; 511eda14cbcSMatt Macy } 512eda14cbcSMatt Macy 513eda14cbcSMatt Macy error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); 514eda14cbcSMatt Macy if (error) 515eda14cbcSMatt Macy goto out; 516eda14cbcSMatt Macy 517eda14cbcSMatt Macy crhold(cr); 518eda14cbcSMatt Macy error = -zfs_readdir(ZTOI(dzp), ctx, cr); 519eda14cbcSMatt Macy crfree(cr); 520eda14cbcSMatt Macy 521eda14cbcSMatt Macy iput(ZTOI(dzp)); 522eda14cbcSMatt Macy out: 523eda14cbcSMatt Macy spl_fstrans_unmark(cookie); 524c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 525eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 526eda14cbcSMatt Macy 527eda14cbcSMatt Macy return (error); 528eda14cbcSMatt Macy } 529eda14cbcSMatt Macy 530eda14cbcSMatt Macy static int 531f9693befSMartin Matuska #ifdef HAVE_USERNS_IOPS_GETATTR 532f9693befSMartin Matuska zpl_shares_getattr_impl(struct user_namespace *user_ns, 533f9693befSMartin Matuska const struct path *path, struct kstat *stat, u32 request_mask, 534f9693befSMartin Matuska unsigned int query_flags) 535d411c1d6SMartin Matuska #elif defined(HAVE_IDMAP_IOPS_GETATTR) 536d411c1d6SMartin Matuska zpl_shares_getattr_impl(struct mnt_idmap *user_ns, 537d411c1d6SMartin Matuska const struct path *path, struct kstat *stat, u32 request_mask, 538d411c1d6SMartin Matuska unsigned int query_flags) 539f9693befSMartin Matuska #else 540eda14cbcSMatt Macy zpl_shares_getattr_impl(const struct path *path, struct kstat *stat, 541eda14cbcSMatt Macy u32 request_mask, unsigned int query_flags) 542f9693befSMartin Matuska #endif 543eda14cbcSMatt Macy { 544c03c5b1cSMartin Matuska (void) request_mask, (void) query_flags; 545eda14cbcSMatt Macy struct inode *ip = path->dentry->d_inode; 546eda14cbcSMatt Macy zfsvfs_t *zfsvfs = ITOZSB(ip); 547eda14cbcSMatt Macy znode_t *dzp; 548eda14cbcSMatt Macy int error; 549eda14cbcSMatt Macy 550c7046f76SMartin Matuska if ((error = zpl_enter(zfsvfs, FTAG)) != 0) 551c7046f76SMartin Matuska return (error); 552eda14cbcSMatt Macy 553eda14cbcSMatt Macy if (zfsvfs->z_shares_dir == 0) { 554d411c1d6SMartin Matuska #if (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) 555c03c5b1cSMartin Matuska #ifdef HAVE_GENERIC_FILLATTR_USERNS 556f9693befSMartin Matuska generic_fillattr(user_ns, path->dentry->d_inode, stat); 557d411c1d6SMartin Matuska #elif defined(HAVE_GENERIC_FILLATTR_IDMAP) 558d411c1d6SMartin Matuska generic_fillattr(user_ns, path->dentry->d_inode, stat); 559abcdc1b9SMartin Matuska #elif defined(HAVE_GENERIC_FILLATTR_IDMAP_REQMASK) 560abcdc1b9SMartin Matuska generic_fillattr(user_ns, request_mask, ip, stat); 561f9693befSMartin Matuska #else 562c03c5b1cSMartin Matuska (void) user_ns; 563c03c5b1cSMartin Matuska #endif 564c03c5b1cSMartin Matuska #else 565eda14cbcSMatt Macy generic_fillattr(path->dentry->d_inode, stat); 566f9693befSMartin Matuska #endif 567eda14cbcSMatt Macy stat->nlink = stat->size = 2; 568eda14cbcSMatt Macy stat->atime = current_time(ip); 569c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 570eda14cbcSMatt Macy return (0); 571eda14cbcSMatt Macy } 572eda14cbcSMatt Macy 573eda14cbcSMatt Macy error = -zfs_zget(zfsvfs, zfsvfs->z_shares_dir, &dzp); 574eda14cbcSMatt Macy if (error == 0) { 575abcdc1b9SMartin Matuska #ifdef HAVE_GENERIC_FILLATTR_IDMAP_REQMASK 576abcdc1b9SMartin Matuska error = -zfs_getattr_fast(user_ns, request_mask, ZTOI(dzp), 577abcdc1b9SMartin Matuska stat); 578abcdc1b9SMartin Matuska #elif (defined(HAVE_USERNS_IOPS_GETATTR) || defined(HAVE_IDMAP_IOPS_GETATTR)) 579f9693befSMartin Matuska error = -zfs_getattr_fast(user_ns, ZTOI(dzp), stat); 580f9693befSMartin Matuska #else 581f9693befSMartin Matuska error = -zfs_getattr_fast(kcred->user_ns, ZTOI(dzp), stat); 582f9693befSMartin Matuska #endif 583eda14cbcSMatt Macy iput(ZTOI(dzp)); 584eda14cbcSMatt Macy } 585eda14cbcSMatt Macy 586c7046f76SMartin Matuska zpl_exit(zfsvfs, FTAG); 587eda14cbcSMatt Macy ASSERT3S(error, <=, 0); 588eda14cbcSMatt Macy 589eda14cbcSMatt Macy return (error); 590eda14cbcSMatt Macy } 591eda14cbcSMatt Macy ZPL_GETATTR_WRAPPER(zpl_shares_getattr); 592eda14cbcSMatt Macy 593eda14cbcSMatt Macy /* 594eda14cbcSMatt Macy * The '.zfs/shares' directory file operations. 595eda14cbcSMatt Macy */ 596eda14cbcSMatt Macy const struct file_operations zpl_fops_shares = { 597eda14cbcSMatt Macy .open = zpl_common_open, 598eda14cbcSMatt Macy .llseek = generic_file_llseek, 599eda14cbcSMatt Macy .read = generic_read_dir, 600eda14cbcSMatt Macy .iterate_shared = zpl_shares_iterate, 601eda14cbcSMatt Macy }; 602eda14cbcSMatt Macy 603eda14cbcSMatt Macy /* 604eda14cbcSMatt Macy * The '.zfs/shares' directory inode operations. 605eda14cbcSMatt Macy */ 606eda14cbcSMatt Macy const struct inode_operations zpl_ops_shares = { 607eda14cbcSMatt Macy .lookup = zpl_shares_lookup, 608eda14cbcSMatt Macy .getattr = zpl_shares_getattr, 609eda14cbcSMatt Macy }; 610