aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sys/zfs_vnops.h2
-rw-r--r--module/zfs/zfs_vnops.c70
-rw-r--r--module/zfs/zpl_file.c34
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,