diff options
-rw-r--r-- | include/sys/zfs_vnops.h | 2 | ||||
-rw-r--r-- | module/zfs/zfs_vnops.c | 70 | ||||
-rw-r--r-- | module/zfs/zpl_file.c | 34 |
3 files changed, 105 insertions, 1 deletions
diff --git a/include/sys/zfs_vnops.h b/include/sys/zfs_vnops.h index bdc54941e..b1c7c9f53 100644 --- a/include/sys/zfs_vnops.h +++ b/include/sys/zfs_vnops.h @@ -36,6 +36,8 @@ extern "C" { #endif +extern int zfs_open(struct inode *ip, int mode, int flag, cred_t *cr); +extern int zfs_close(struct inode *ip, int flag, cred_t *cr); extern int zfs_read(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr); extern int zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr); extern int zfs_access(struct inode *ip, int mode, int flag, cred_t *cr); diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 29ddaf0b7..cb66741c2 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -163,6 +163,76 @@ * return (error); // done, report error */ +/* + * Virus scanning is unsupported. It would be possible to add a hook + * here to performance the required virus scan. This could be done + * entirely in the kernel or potentially as an update to invoke a + * scanning utility. + */ +static int +zfs_vscan(struct inode *ip, cred_t *cr, int async) +{ + return (0); +} + +/* ARGSUSED */ +int +zfs_open(struct inode *ip, int mode, int flag, cred_t *cr) +{ + znode_t *zp = ITOZ(ip); + zfs_sb_t *zsb = ITOZSB(ip); + + ZFS_ENTER(zsb); + ZFS_VERIFY_ZP(zp); + + /* Honor ZFS_APPENDONLY file attribute */ + if ((mode & FMODE_WRITE) && (zp->z_pflags & ZFS_APPENDONLY) && + ((flag & O_APPEND) == 0)) { + ZFS_EXIT(zsb); + return (EPERM); + } + + /* Virus scan eligible files on open */ + if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) && + !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0) { + if (zfs_vscan(ip, cr, 0) != 0) { + ZFS_EXIT(zsb); + return (EACCES); + } + } + + /* Keep a count of the synchronous opens in the znode */ + if (flag & O_SYNC) + atomic_inc_32(&zp->z_sync_cnt); + + ZFS_EXIT(zsb); + return (0); +} +EXPORT_SYMBOL(zfs_open); + +/* ARGSUSED */ +int +zfs_close(struct inode *ip, int flag, cred_t *cr) +{ + znode_t *zp = ITOZ(ip); + zfs_sb_t *zsb = ITOZSB(ip); + + ZFS_ENTER(zsb); + ZFS_VERIFY_ZP(zp); + + /* Decrement the synchronous opens in the znode */ + if (flag & O_SYNC) + zp->z_sync_cnt = 0; + + if (!zfs_has_ctldir(zp) && zsb->z_vscan && S_ISREG(ip->i_mode) && + !(zp->z_pflags & ZFS_AV_QUARANTINED) && zp->z_size > 0) + VERIFY(zfs_vscan(ip, cr, 1) == 0); + + ZFS_EXIT(zsb); + return (0); +} +EXPORT_SYMBOL(zfs_close); + #if defined(_KERNEL) /* * When a file is memory mapped, we must keep the IO data synchronized diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index ed6704bb2..d76e62d43 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -30,6 +30,37 @@ static int +zpl_open(struct inode *ip, struct file *filp) +{ + cred_t *cr; + int error; + + cr = (cred_t *)get_current_cred(); + error = -zfs_open(ip, filp->f_mode, filp->f_flags, cr); + put_cred(cr); + ASSERT3S(error, <=, 0); + + if (error) + return (error); + + return generic_file_open(ip, filp); +} + +static int +zpl_release(struct inode *ip, struct file *filp) +{ + cred_t *cr; + int error; + + cr = (cred_t *)get_current_cred(); + error = -zfs_close(ip, filp->f_flags, cr); + put_cred(cr); + ASSERT3S(error, <=, 0); + + return (error); +} + +static int zpl_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; @@ -316,7 +347,8 @@ const struct address_space_operations zpl_address_space_operations = { }; const struct file_operations zpl_file_operations = { - .open = generic_file_open, + .open = zpl_open, + .release = zpl_release, .llseek = generic_file_llseek, .read = zpl_read, .write = zpl_write, |