From 27ece2ee4d9a3e814edfc6ff7cbbc56537d94b59 Mon Sep 17 00:00:00 2001 From: Matthew Macy Date: Wed, 6 Nov 2019 10:54:25 -0800 Subject: [PATCH] Move platform specific parts of zfs_znode.h to platform code Some of the znode fields are different and functions consuming an inode don't exist on FreeBSD. Reviewed-by: Brian Behlendorf Reviewed-by: Jorgen Lundman Signed-off-by: Matt Macy Closes #9536 --- include/os/linux/zfs/sys/Makefile.am | 1 + include/os/linux/zfs/sys/zfs_znode_impl.h | 164 ++++++++++++++++++++++ include/sys/zfs_znode.h | 149 ++------------------ module/os/linux/zfs/zfs_acl.c | 4 +- module/zfs/zfs_rlock.c | 15 ++ 5 files changed, 194 insertions(+), 139 deletions(-) create mode 100644 include/os/linux/zfs/sys/zfs_znode_impl.h diff --git a/include/os/linux/zfs/sys/Makefile.am b/include/os/linux/zfs/sys/Makefile.am index e061c5ab1..cb309d7fc 100644 --- a/include/os/linux/zfs/sys/Makefile.am +++ b/include/os/linux/zfs/sys/Makefile.am @@ -20,6 +20,7 @@ KERNEL_H = \ $(top_srcdir)/include/os/linux/zfs/sys/zfs_dir.h \ $(top_srcdir)/include/os/linux/zfs/sys/zfs_vfsops.h \ $(top_srcdir)/include/os/linux/zfs/sys/zfs_vnops.h \ + $(top_srcdir)/include/os/linux/zfs/sys/zfs_znode_impl.h \ $(top_srcdir)/include/os/linux/zfs/sys/zpl.h if CONFIG_KERNEL diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h new file mode 100644 index 000000000..0ecfb0a90 --- /dev/null +++ b/include/os/linux/zfs/sys/zfs_znode_impl.h @@ -0,0 +1,164 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + */ + +#ifndef _SYS_ZFS_ZNODE_IMPL_H +#define _SYS_ZFS_ZNODE_IMPL_H + +#ifndef _KERNEL +#error "no user serviceable parts within" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZNODE_OS_FIELDS \ + struct inode z_inode; + + +/* + * Convert between znode pointers and inode pointers + */ +#define ZTOI(znode) (&((znode)->z_inode)) +#define ITOZ(inode) (container_of((inode), znode_t, z_inode)) +#define ZTOZSB(znode) ((zfsvfs_t *)(ZTOI(znode)->i_sb->s_fs_info)) +#define ITOZSB(inode) ((zfsvfs_t *)((inode)->i_sb->s_fs_info)) + +#define ZTOTYPE(zp) (ZTOI(zp)->i_mode) +#define ZTOGID(zp) (ZTOI(zp)->i_gid) +#define ZTOUID(zp) (ZTOI(zp)->i_uid) +#define ZTONLNK(zp) (ZTOI(zp)->i_nlink) + +#define Z_ISBLK(type) S_ISBLK(type) +#define Z_ISCHR(type) S_ISCHR(type) +#define Z_ISLNK(type) S_ISLNK(type) +#define Z_ISDEV(type) (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type)) + +/* Called on entry to each ZFS inode and vfs operation. */ +#define ZFS_ENTER_ERROR(zfsvfs, error) \ +do { \ + rrm_enter_read(&(zfsvfs)->z_teardown_lock, FTAG); \ + if ((zfsvfs)->z_unmounted) { \ + ZFS_EXIT(zfsvfs); \ + return (error); \ + } \ +} while (0) +#define ZFS_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, EIO) +#define ZPL_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, -EIO) + +/* Must be called before exiting the operation. */ +#define ZFS_EXIT(zfsvfs) \ +do { \ + rrm_exit(&(zfsvfs)->z_teardown_lock, FTAG); \ +} while (0) +#define ZPL_EXIT(zfsvfs) ZFS_EXIT(zfsvfs) + +/* Verifies the znode is valid. */ +#define ZFS_VERIFY_ZP_ERROR(zp, error) \ +do { \ + if ((zp)->z_sa_hdl == NULL) { \ + ZFS_EXIT(ZTOZSB(zp)); \ + return (error); \ + } \ +} while (0) +#define ZFS_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, EIO) +#define ZPL_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, -EIO) + +/* + * Macros for dealing with dmu_buf_hold + */ +#define ZFS_OBJ_MTX_SZ 64 +#define ZFS_OBJ_MTX_MAX (1024 * 1024) +#define ZFS_OBJ_HASH(zfsvfs, obj) ((obj) & ((zfsvfs->z_hold_size) - 1)) + +extern unsigned int zfs_object_mutex_size; + +/* + * Encode ZFS stored time values from a struct timespec / struct timespec64. + */ +#define ZFS_TIME_ENCODE(tp, stmp) \ +do { \ + (stmp)[0] = (uint64_t)(tp)->tv_sec; \ + (stmp)[1] = (uint64_t)(tp)->tv_nsec; \ +} while (0) + +#if defined(HAVE_INODE_TIMESPEC64_TIMES) +/* + * Decode ZFS stored time values to a struct timespec64 + * 4.18 and newer kernels. + */ +#define ZFS_TIME_DECODE(tp, stmp) \ +do { \ + (tp)->tv_sec = (time64_t)(stmp)[0]; \ + (tp)->tv_nsec = (long)(stmp)[1]; \ +} while (0) +#else +/* + * Decode ZFS stored time values to a struct timespec + * 4.17 and older kernels. + */ +#define ZFS_TIME_DECODE(tp, stmp) \ +do { \ + (tp)->tv_sec = (time_t)(stmp)[0]; \ + (tp)->tv_nsec = (long)(stmp)[1]; \ +} while (0) +#endif /* HAVE_INODE_TIMESPEC64_TIMES */ + +struct znode; + +extern int zfs_sync(struct super_block *, int, cred_t *); +extern int zfs_inode_alloc(struct super_block *, struct inode **ip); +extern void zfs_inode_destroy(struct inode *); +extern void zfs_inode_update(struct znode *); +extern void zfs_mark_inode_dirty(struct inode *); +extern boolean_t zfs_relatime_need_update(const struct inode *); + +#if defined(HAVE_UIO_RW) +extern caddr_t zfs_map_page(page_t *, enum seg_rw); +extern void zfs_unmap_page(page_t *, caddr_t); +#endif /* HAVE_UIO_RW */ + +extern zil_get_data_t zfs_get_data; +extern zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE]; +extern int zfsfstype; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_ZFS_ZNODE_IMPL_H */ diff --git a/include/sys/zfs_znode.h b/include/sys/zfs_znode.h index 79c4137fc..0e8d44637 100644 --- a/include/sys/zfs_znode.h +++ b/include/sys/zfs_znode.h @@ -27,18 +27,6 @@ #ifndef _SYS_FS_ZFS_ZNODE_H #define _SYS_FS_ZFS_ZNODE_H -#ifdef _KERNEL -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif #include #include #include @@ -169,12 +157,16 @@ extern "C" { #define ZFS_DIRENT_TYPE(de) BF64_GET(de, 60, 4) #define ZFS_DIRENT_OBJ(de) BF64_GET(de, 0, 48) +extern int zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len); + +#ifdef _KERNEL +#include + /* * Directory entry locks control access to directory entries. * They are used to protect creates, deletes, and renames. * Each directory znode has a mutex and a list of locked names. */ -#ifdef _KERNEL typedef struct zfs_dirlock { char *dl_name; /* directory entry being locked */ uint32_t dl_sharecnt; /* 0 if exclusive, > 0 if shared */ @@ -217,7 +209,12 @@ typedef struct znode { uint64_t z_projid; /* project ID */ list_node_t z_link_node; /* all znodes in fs link */ sa_handle_t *z_sa_hdl; /* handle to sa data */ - struct inode z_inode; /* generic vfs inode */ + + /* + * Platform specific field, defined by each platform and only + * accessable from platform specific code. + */ + ZNODE_OS_FIELDS; } znode_t; typedef struct znode_hold { @@ -234,110 +231,6 @@ zfs_inherit_projid(znode_t *dzp) ZFS_DEFAULT_PROJID); } -/* - * Range locking rules - * -------------------- - * 1. When truncating a file (zfs_create, zfs_setattr, zfs_space) the whole - * file range needs to be locked as RL_WRITER. Only then can the pages be - * freed etc and zp_size reset. zp_size must be set within range lock. - * 2. For writes and punching holes (zfs_write & zfs_space) just the range - * being written or freed needs to be locked as RL_WRITER. - * Multiple writes at the end of the file must coordinate zp_size updates - * to ensure data isn't lost. A compare and swap loop is currently used - * to ensure the file size is at least the offset last written. - * 3. For reads (zfs_read, zfs_get_data & zfs_putapage) just the range being - * read needs to be locked as RL_READER. A check against zp_size can then - * be made for reading beyond end of file. - */ - -/* - * Convert between znode pointers and inode pointers - */ -#define ZTOI(znode) (&((znode)->z_inode)) -#define ITOZ(inode) (container_of((inode), znode_t, z_inode)) -#define ZTOZSB(znode) ((zfsvfs_t *)(ZTOI(znode)->i_sb->s_fs_info)) -#define ITOZSB(inode) ((zfsvfs_t *)((inode)->i_sb->s_fs_info)) - -#define ZTOTYPE(zp) (ZTOI(zp)->i_mode) -#define ZTOGID(zp) (ZTOI(zp)->i_gid) -#define ZTOUID(zp) (ZTOI(zp)->i_uid) -#define ZTONLNK(zp) (ZTOI(zp)->i_nlink) - -#define Z_ISBLK(type) S_ISBLK(type) -#define Z_ISCHR(type) S_ISCHR(type) -#define Z_ISLNK(type) S_ISLNK(type) -#define S_ISDEV(type) (S_ISCHR(type) || S_ISBLK(type) || S_ISFIFO(type)) - -/* Called on entry to each ZFS inode and vfs operation. */ -#define ZFS_ENTER_ERROR(zfsvfs, error) \ -do { \ - rrm_enter_read(&(zfsvfs)->z_teardown_lock, FTAG); \ - if ((zfsvfs)->z_unmounted) { \ - ZFS_EXIT(zfsvfs); \ - return (error); \ - } \ -} while (0) -#define ZFS_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, EIO) -#define ZPL_ENTER(zfsvfs) ZFS_ENTER_ERROR(zfsvfs, -EIO) - -/* Must be called before exiting the operation. */ -#define ZFS_EXIT(zfsvfs) \ -do { \ - rrm_exit(&(zfsvfs)->z_teardown_lock, FTAG); \ -} while (0) -#define ZPL_EXIT(zfsvfs) ZFS_EXIT(zfsvfs) - -/* Verifies the znode is valid. */ -#define ZFS_VERIFY_ZP_ERROR(zp, error) \ -do { \ - if ((zp)->z_sa_hdl == NULL) { \ - ZFS_EXIT(ZTOZSB(zp)); \ - return (error); \ - } \ -} while (0) -#define ZFS_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, EIO) -#define ZPL_VERIFY_ZP(zp) ZFS_VERIFY_ZP_ERROR(zp, -EIO) - -/* - * Macros for dealing with dmu_buf_hold - */ -#define ZFS_OBJ_MTX_SZ 64 -#define ZFS_OBJ_MTX_MAX (1024 * 1024) -#define ZFS_OBJ_HASH(zfsvfs, obj) ((obj) & ((zfsvfs->z_hold_size) - 1)) - -extern unsigned int zfs_object_mutex_size; - -/* - * Encode ZFS stored time values from a struct timespec / struct timespec64. - */ -#define ZFS_TIME_ENCODE(tp, stmp) \ -do { \ - (stmp)[0] = (uint64_t)(tp)->tv_sec; \ - (stmp)[1] = (uint64_t)(tp)->tv_nsec; \ -} while (0) - -#if defined(HAVE_INODE_TIMESPEC64_TIMES) -/* - * Decode ZFS stored time values to a struct timespec64 - * 4.18 and newer kernels. - */ -#define ZFS_TIME_DECODE(tp, stmp) \ -do { \ - (tp)->tv_sec = (time64_t)(stmp)[0]; \ - (tp)->tv_nsec = (long)(stmp)[1]; \ -} while (0) -#else -/* - * Decode ZFS stored time values to a struct timespec - * 4.17 and older kernels. - */ -#define ZFS_TIME_DECODE(tp, stmp) \ -do { \ - (tp)->tv_sec = (time_t)(stmp)[0]; \ - (tp)->tv_nsec = (long)(stmp)[1]; \ -} while (0) -#endif /* HAVE_INODE_TIMESPEC64_TIMES */ - /* * Timestamp defines */ @@ -362,17 +255,11 @@ extern void zfs_zinactive(znode_t *); extern void zfs_znode_delete(znode_t *, dmu_tx_t *); extern void zfs_remove_op_tables(void); extern int zfs_create_op_tables(void); -extern int zfs_sync(struct super_block *, int, cred_t *); extern dev_t zfs_cmpldev(uint64_t); extern int zfs_get_zplprop(objset_t *os, zfs_prop_t prop, uint64_t *value); extern int zfs_get_stats(objset_t *os, nvlist_t *nv); extern boolean_t zfs_get_vfs_flag_unmounted(objset_t *os); extern void zfs_znode_dmu_fini(znode_t *); -extern int zfs_inode_alloc(struct super_block *, struct inode **ip); -extern void zfs_inode_destroy(struct inode *); -extern void zfs_inode_update(znode_t *); -extern void zfs_mark_inode_dirty(struct inode *); -extern boolean_t zfs_relatime_need_update(const struct inode *); extern void zfs_log_create(zilog_t *zilog, dmu_tx_t *tx, uint64_t txtype, znode_t *dzp, znode_t *zp, char *name, vsecattr_t *, zfs_fuid_info_t *, @@ -400,19 +287,7 @@ extern void zfs_log_acl(zilog_t *zilog, dmu_tx_t *tx, znode_t *zp, extern void zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx); extern void zfs_upgrade(zfsvfs_t *zfsvfs, dmu_tx_t *tx); -#if defined(HAVE_UIO_RW) -extern caddr_t zfs_map_page(page_t *, enum seg_rw); -extern void zfs_unmap_page(page_t *, caddr_t); -#endif /* HAVE_UIO_RW */ - -extern zil_get_data_t zfs_get_data; -extern zil_replay_func_t *zfs_replay_vector[TX_MAX_TYPE]; -extern int zfsfstype; - -#endif /* _KERNEL */ - -extern int zfs_obj_to_path(objset_t *osp, uint64_t obj, char *buf, int len); - +#endif #ifdef __cplusplus } #endif diff --git a/module/os/linux/zfs/zfs_acl.c b/module/os/linux/zfs/zfs_acl.c index 67efee175..4c21350c0 100644 --- a/module/os/linux/zfs/zfs_acl.c +++ b/module/os/linux/zfs/zfs_acl.c @@ -2159,8 +2159,8 @@ static int zfs_zaccess_dataset_check(znode_t *zp, uint32_t v4_mode) { if ((v4_mode & WRITE_MASK) && (zfs_is_readonly(ZTOZSB(zp))) && - (!S_ISDEV(ZTOI(zp)->i_mode) || - (S_ISDEV(ZTOI(zp)->i_mode) && (v4_mode & WRITE_MASK_ATTRS)))) { + (!Z_ISDEV(ZTOI(zp)->i_mode) || + (Z_ISDEV(ZTOI(zp)->i_mode) && (v4_mode & WRITE_MASK_ATTRS)))) { return (SET_ERROR(EROFS)); } diff --git a/module/zfs/zfs_rlock.c b/module/zfs/zfs_rlock.c index 3158f4320..091b37f9f 100644 --- a/module/zfs/zfs_rlock.c +++ b/module/zfs/zfs_rlock.c @@ -38,6 +38,20 @@ * rangelock_reduce(lr, off, len); // optional * rangelock_exit(lr); * + * Range locking rules + * -------------------- + * 1. When truncating a file (zfs_create, zfs_setattr, zfs_space) the whole + * file range needs to be locked as RL_WRITER. Only then can the pages be + * freed etc and zp_size reset. zp_size must be set within range lock. + * 2. For writes and punching holes (zfs_write & zfs_space) just the range + * being written or freed needs to be locked as RL_WRITER. + * Multiple writes at the end of the file must coordinate zp_size updates + * to ensure data isn't lost. A compare and swap loop is currently used + * to ensure the file size is at least the offset last written. + * 3. For reads (zfs_read, zfs_get_data & zfs_putapage) just the range being + * read needs to be locked as RL_READER. A check against zp_size can then + * be made for reading beyond end of file. + * * AVL tree * -------- * An AVL tree is used to maintain the state of the existing ranges @@ -99,6 +113,7 @@ #include #include + /* * AVL comparison function used to order range locks * Locks are ordered on the start offset of the range.