diff --git a/README.md b/README.md
index 8b03786..0e466f2 100644
--- a/README.md
+++ b/README.md
@@ -12,126 +12,17 @@ fanotify has features spanning different kernel versions -
 - For Linux kernel versions 5.1 - 5.8 additional information about the underlying filesystem object is correlated to an event.
 - For Linux kernel version 5.9 or later the modified file name is made available in the event.
 
-## Example: Listener watching for events on a directory
+## Examples
 
-```
-package main
-
-import (
-	"flag"
-	"fmt"
-	"os"
-
-	"github.com/opcoder0/fanotify"
-)
-
-func main() {
-	var listenPath string
-
-	flag.StringVar(&listenPath, "listen-path", "", "path to watch events")
-	flag.Parse()
-	if listenPath == "" {
-		fmt.Println("missing listen path")
-		os.Exit(1)
-	}
-	mountPoint := "/"
-	listener, err := fanotify.NewListener(mountPoint, false)
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-	fmt.Println("Listening to events for:", listenPath)
-	var eventTypes EventType
-	eventTypes =
-		fanotify.FileAccessed |
-			fanotify.FileOrDirectoryAccessed |
-			fanotify.FileModified |
-			fanotify.FileOpenedForExec |
-			fanotify.FileAttribChanged |
-			fanotify.FileOrDirectoryAttribChanged |
-			fanotify.FileCreated |
-			fanotify.FileOrDirectoryCreated |
-			fanotify.FileDeleted |
-			fanotify.FileOrDirectoryDeleted |
-			fanotify.WatchedFileDeleted |
-			fanotify.WatchedFileOrDirectoryDeleted |
-			fanotify.FileMovedFrom |
-			fanotify.FileOrDirectoryMovedFrom |
-			fanotify.FileMovedTo |
-			fanotify.FileOrDirectoryMovedTo |
-			fanotify.WatchedFileMoved |
-			fanotify.WatchedFileOrDirectoryMoved
-	listener.AddWatch(listenPath, eventTypes)
-	go listener.Start()
-	i := 1
-	for event := range listener.Events {
-		fmt.Println(event)
-		if i == 5 {
-			fmt.Println("Enough events. Stopping...")
-			listener.Stop()
-			break
-		}
-		i++
-	}
-}
-```
-
-## Example: Listener watching for events on a mount point
-
-```
-package main
-
-import (
-	"flag"
-	"fmt"
-	"os"
-
-	"github.com/opcoder0/fanotify"
-)
-
-func main() {
-	var mountPoint string
+Example code for different use-cases can be found here https://github.com/opcoder0/fanotify-examples
 
-	flag.StringVar(&mountPoint, "mount-path", "", "mount point path")
-	flag.Parse()
-
-	if mountPoint == "" {
-		fmt.Println("missing mount path")
-		os.Exit(1)
-	}
-	listener, err := fanotify.NewListener(mountPoint, true)
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-	fmt.Println("Listening to events for:", mountPoint)
-	var eventTypes fanotify.EventType
-	eventTypes = fanotify.FileAccessed |
-			fanotify.FileOrDirectoryAccessed |
-			fanotify.FileModified |
-			fanotify.FileOpenedForExec |
-			fanotify.FileOpened
-	err = listener.MarkMount(eventTypes, false)
-	if err != nil {
-		fmt.Println("MarkMount:", err)
-		os.Exit(1)
-	}
-	go listener.Start()
-	for event := range listener.Events {
-		fmt.Println(event)
-	}
-	listener.Stop()
-}
-```
 ## Known Issues
 
 Certain flag combinations / event types cause issues with event reporting.
 
-- `fanotify.FileCreated` (`unix.FAN_CREATE`) cannot be or-ed / combined with `fanotify.FileClosed` (`unix.FAN_CLOSE_WRITE` or `unix.FAN_CLOSE_NOWRITE`). The `fanotify` event notification group does not generate any event for this combination.
-
-- Using `fanotify.FileOpened` with any of the event types containing `OrDirectory` (`unix.FAN_ONDIR`) causes an event flood for the directory and then stopping raising any events at all.
-
-- `fanotifyFileOrDirectoryOpened` with any of the other event types causes an event flood for the directory and then stopping raising any events at all.
+- `fanotify.FileCreated` cannot be or-ed / combined with `fanotify.FileClosed`. The `fanotify` event notification group does not generate any event for this combination.
+- Using `fanotify.FileOpened` with any of the event types containing `OrDirectory` causes numerous duplicate events for the path.
+- `fanotifyFileOrDirectoryOpened` with any of the other event types causes numerous duplicate events for the path.
 
 ## Tests
 
diff --git a/doc.go b/doc.go
index c25bd51..5de4b89 100644
--- a/doc.go
+++ b/doc.go
@@ -1,4 +1,4 @@
-// Package fanotify library provides a simple API to monitor filesystem for events.
+// Package fanotify library provides a simple API to monitor filesystem for notification and permission events.
 //
 // The listener is initialized with flags automatically based on the kernel version. The mark flag features that specify the
 // the events to monitor a file/directory are validated and checked for valid combinations and validated against the kernel
diff --git a/doc_test.go b/doc_test.go
index c7d989f..c7d038d 100644
--- a/doc_test.go
+++ b/doc_test.go
@@ -7,14 +7,14 @@ import (
 )
 
 func ExampleNewListener() {
-	if _, err := fanotify.NewListener("/", true); err != nil {
+	if _, err := fanotify.NewListener("/", true, fanotify.PostContent); err != nil {
 		log.Fatal("Cannot create listener for mount /", err)
 	}
 }
 
 func ExampleListener_AddWatch() {
 	var listener *fanotify.Listener
-	listener, err := fanotify.NewListener("/", false)
+	listener, err := fanotify.NewListener("/", false, fanotify.PermissionNone)
 	if err != nil {
 		log.Fatal("Cannot create listener for mount /", err)
 	}
@@ -25,7 +25,7 @@ func ExampleListener_AddWatch_all() {
 	var listener *fanotify.Listener
 	var eventTypes fanotify.EventType
 
-	listener, err := fanotify.NewListener("/", false)
+	listener, err := fanotify.NewListener("/", false, fanotify.PermissionNone)
 	if err != nil {
 		log.Fatal("Cannot create listener for path /", err)
 	}
diff --git a/fanotify_api.go b/fanotify_api.go
index d730718..5226676 100644
--- a/fanotify_api.go
+++ b/fanotify_api.go
@@ -4,6 +4,8 @@
 package fanotify
 
 import (
+	"bytes"
+	"encoding/binary"
 	"errors"
 	"fmt"
 	"os"
@@ -17,8 +19,6 @@ var (
 	ErrCapSysAdmin = errors.New("require CAP_SYS_ADMIN capability")
 	// ErrInvalidFlagCombination indicates the bit/combination of flags are invalid
 	ErrInvalidFlagCombination = errors.New("invalid flag bitmask")
-	// ErrNilListener indicates the listener is nil
-	ErrNilListener = errors.New("nil listener")
 	// ErrUnsupportedOnKernelVersion indicates the feature/flag is unavailable for the current kernel version
 	ErrUnsupportedOnKernelVersion = errors.New("feature unsupported on current kernel version")
 	// ErrWatchPath indicates path needs to be specified for watching
@@ -28,8 +28,28 @@ var (
 // EventType represents an event / operation on a particular file/directory
 type EventType uint64
 
-// Event represents a notification from the kernel for the file, directory
-// or a filesystem marked for watching.
+// PermissionType represents value indicating when the permission event must be requested.
+type PermissionType int
+
+const (
+	// PermissionNone is used to indicate the listener is for notification events only.
+	PermissionNone PermissionType = 0
+	// PreContent is intended for event listeners that
+	// need to access files before they contain their final data.
+	PreContent PermissionType = 1
+	// PostContent is intended for event listeners that
+	// need to access files when they already contain their final content.
+	PostContent PermissionType = 2
+)
+
+// Event represents a notification or a permission event from the kernel for the file,
+// directory marked for watching.
+// Notification events are merely informative and require
+// no action to be taken by the receiving application with the exception being that the
+// file descriptor provided within the event must be closed.
+// Permission events are requests to the receiving application to decide whether permission
+// for a file access shall be granted. For these events, the recipient must write a
+// response which decides whether access is granted or not.
 type Event struct {
 	// Fd is the open file descriptor for the file/directory being watched
 	Fd int
@@ -45,8 +65,9 @@ type Event struct {
 	Pid int
 }
 
-// Listener represents a fanotify notification group that holds a list of files,
-// directories or a mountpoint for which events shall be created.
+// Listener represents a generic notification group that holds a list of files,
+// directories or a mountpoint for which notification or permission
+// events shall be created.
 type Listener struct {
 	// fd returned by fanotify_init
 	fd int
@@ -57,37 +78,56 @@ type Listener struct {
 	kernelMajorVersion int
 	kernelMinorVersion int
 	entireMount        bool
+	notificationOnly   bool
 	watches            map[string]bool
 	stopper            struct {
 		r *os.File
 		w *os.File
 	}
-	// Events a buffered channel holding fanotify notifications for the watched file/directory.
+	// Events holds either notification events for the watched file/directory.
 	Events chan Event
+	// PermissionEvents holds permission request events for the watched file/directory.
+	PermissionEvents chan Event
 }
 
-// NewListener returns a fanotify listener from which filesystem events
-// can be read. Each listener supports listening to events
-// under a single mountpoint.
-//
-// For cases where multiple mountpoints need to be monitored
+// NewListener returns a fanotify listener from which filesystem
+// notification events can be read. Each listener
+// supports listening to events under a single mount point.
+// For cases where multiple mount points need to be monitored
 // multiple listener instances need to be used.
 //
-// mountPoint can be any file/directory under the mount point being watched.
-// entireMount when "true" monitors the entire mount point for marked
-// events which includes all directories, subdirectories, and the
-// contained files of the mount point. Passing "false" allows specifying
-// multiple paths (files/directories)
-// under this mount point for monitoring filesystem events using AddWatch.
+// Notification events are merely informative and require
+// no action to be taken by the receiving application with the
+// exception being that the file descriptor provided within the
+// event must be closed.
+//
+// Permission events are requests to the receiving application to
+// decide whether permission for a file access shall be granted.
+// For these events, the recipient must write a response which decides
+// whether access is granted or not.
+//
+// - mountPoint can be any file/directory under the mount point being
+//   watched.
+// - entireMount initializes the listener to monitor either the
+//   the entire mount point (when true) or allows adding files
+//   or directories to the listener's watch list (when false).
+// - permType initializes the listener either notification events
+//   or both notification and permission events.
+//   Passing [PreContent] value allows the receipt of events
+//   notifying that a file has been accessed and events for permission
+//   decisions if a file may be accessed. It is intended for event listeners
+//   that need to access files before they contain their final data. Passing
+//   [PostContent] is intended for event listeners that need to access
+//   files when they already contain their final content.
 //
-// The function returns a new instance of the listener. The fanotify flags are set
-// based on the running kernel version. [ErrCapSysAdmin] is returned if the process does not
-// have CAP_SYS_ADM capability.
+// The function returns a new instance of the listener. The fanotify flags
+// are set based on the running kernel version. [ErrCapSysAdmin] is returned
+// if the process does not have CAP_SYS_ADM capability.
 //
 //  - For Linux kernel version 5.0 and earlier no additional information about the underlying filesystem object is available.
 //  - For Linux kernel versions 5.1 till 5.8 (inclusive) additional information about the underlying filesystem object is correlated to an event.
 //  - For Linux kernel version 5.9 or later the modified file name is made available in the event.
-func NewListener(mountPoint string, entireMount bool) (*Listener, error) {
+func NewListener(mountPoint string, entireMount bool, permType PermissionType) (*Listener, error) {
 	capSysAdmin, err := checkCapSysAdmin()
 	if err != nil {
 		return nil, err
@@ -95,13 +135,20 @@ func NewListener(mountPoint string, entireMount bool) (*Listener, error) {
 	if !capSysAdmin {
 		return nil, ErrCapSysAdmin
 	}
-	return newListener(mountPoint, entireMount)
+	isNotificationListener := true
+	if permType == PreContent || permType == PostContent {
+		isNotificationListener = false
+	}
+	return newListener(mountPoint, entireMount, isNotificationListener, permType)
 }
 
 // Start starts the listener and polls the fanotify event notification group for marked events.
-// The events are pushed into the Listener's `Events` buffered channel.
+// The events are pushed into the Listener's Events channel.
 func (l *Listener) Start() {
 	var fds [2]unix.PollFd
+	if l == nil {
+		panic("nil listener")
+	}
 	// Fanotify Fd
 	fds[0].Fd = int32(l.fd)
 	fds[0].Events = unix.POLLIN
@@ -148,68 +195,76 @@ func (l *Listener) Stop() {
 	close(l.Events)
 }
 
-// MarkMount adds, modifies or removes the fanotify mark (eventTypes) for the entire
-// mount point. Passing true to remove, removes the mark from the mount point.
+// WatchMount adds or modifies the notification marks for the entire
+// mount point.
 // This method returns an [ErrWatchPath] if the listener was not initialized to monitor
 // the entire mount point. To mark specific files or directories use [AddWatch] method.
-// The entire mount cannot be monitored for any events for which new directory modification
-// events are provided. Passing any of these directory modification flags in eventTypes
-// will return [ErrInvalidFlagCombination] error. Valid eventTypes are
-// [FileAccessed], [FileOrDirectoryAccessed], [FileModified], [FileOpenedForExec]
-// [FileOpened], [FileOrDirectoryOpened].
-func (l *Listener) MarkMount(eventTypes EventType, remove bool) error {
-	if l.entireMount == false {
-		return ErrWatchPath
-	}
-	if eventTypes.Has(FileAttribChanged) ||
-		eventTypes.Has(FileOrDirectoryAttribChanged) ||
-		eventTypes.Has(FileCreated) ||
-		eventTypes.Has(FileOrDirectoryCreated) ||
-		eventTypes.Has(FileDeleted) ||
-		eventTypes.Has(FileOrDirectoryDeleted) ||
-		eventTypes.Has(WatchedFileDeleted) ||
-		eventTypes.Has(WatchedFileOrDirectoryDeleted) ||
-		eventTypes.Has(FileMovedTo) ||
-		eventTypes.Has(FileMovedFrom) ||
-		eventTypes.Has(WatchedFileMoved) ||
-		eventTypes.Has(WatchedFileDeleted) {
-		return ErrInvalidFlagCombination
-	}
-	if remove {
-		return l.fanotifyMark(l.mountpoint.Name(), unix.FAN_MARK_REMOVE|unix.FAN_MARK_MOUNT, uint64(eventTypes), false)
-	}
-	return l.fanotifyMark(l.mountpoint.Name(), unix.FAN_MARK_ADD|unix.FAN_MARK_MOUNT, uint64(eventTypes), false)
+// The following event types are considered invalid and WatchMount returns [ErrInvalidFlagCombination]
+// for - [FileCreated], [FileAttribChanged], [FileMovedTo], [FileMovedFrom], [WatchedFileDeleted],
+// [WatchedFileOrDirectoryDeleted], [FileDeleted], [FileOrDirectoryDeleted]
+func (l *Listener) WatchMount(eventTypes EventType) error {
+	return l.fanotifyMark(l.mountpoint.Name(), unix.FAN_MARK_ADD|unix.FAN_MARK_MOUNT, uint64(eventTypes))
+}
+
+// UnwatchMount removes the notification marks for the entire mount point.
+// This method returns an [ErrWatchPath] if the listener was not initialized to monitor
+// the entire mount point. To unmark specific files or directories use [DeleteWatch] method.
+func (l *Listener) UnwatchMount(eventTypes EventType) error {
+	return l.fanotifyMark(l.mountpoint.Name(), unix.FAN_MARK_REMOVE|unix.FAN_MARK_MOUNT, uint64(eventTypes))
 }
 
 // AddWatch adds or modifies the fanotify mark for the specified path.
 // The events are only raised for the specified directory and does raise events
 // for subdirectories. Calling AddWatch to mark the entire mountpoint results in
-// [os.ErrInvalid]. To mark the entire mount point use [MarkMount] method.
+// [os.ErrInvalid]. To watch the entire mount point use [WatchMount] method.
 // Certain flag combinations are known to cause issues.
 //  - [FileCreated] cannot be or-ed / combined with [FileClosed]. The fanotify system does not generate any event for this combination.
 //  - [FileOpened] with any of the event types containing OrDirectory causes an event flood for the directory and then stopping raising any events at all.
 //  - [FileOrDirectoryOpened] with any of the other event types causes an event flood for the directory and then stopping raising any events at all.
 func (l *Listener) AddWatch(path string, eventTypes EventType) error {
+	if l == nil {
+		panic("nil listener")
+	}
 	if l.entireMount {
 		return os.ErrInvalid
 	}
-	return l.fanotifyMark(path, unix.FAN_MARK_ADD, uint64(eventTypes|unix.FAN_EVENT_ON_CHILD), false)
+	return l.fanotifyMark(path, unix.FAN_MARK_ADD, uint64(eventTypes|unix.FAN_EVENT_ON_CHILD))
+}
+
+// Allow sends an "allowed" response to the permission request event.
+func (l *Listener) Allow(e Event) {
+	var response unix.FanotifyResponse
+	response.Fd = int32(e.Fd)
+	response.Response = unix.FAN_ALLOW
+	buf := new(bytes.Buffer)
+	binary.Write(buf, binary.LittleEndian, &response)
+	unix.Write(l.fd, buf.Bytes())
+}
+
+// Deny sends an "denied" response to the permission request event.
+func (l *Listener) Deny(e Event) {
+	var response unix.FanotifyResponse
+	response.Fd = int32(e.Fd)
+	response.Response = unix.FAN_DENY
+	buf := new(bytes.Buffer)
+	binary.Write(buf, binary.LittleEndian, &response)
+	unix.Write(l.fd, buf.Bytes())
 }
 
-// DeleteWatch removes or modifies the fanotify mark for the specified path.
+// DeleteWatch removes/unmarks the fanotify mark for the specified path.
 // Calling DeleteWatch on the listener initialized to monitor the entire mount point
-// results in [os.ErrInvalid]. To modify the mark for the entire mount point use [MarkMount] method.
+// results in [os.ErrInvalid]. Use [UnwatchMount] for deleting marks on the mount point.
 func (l *Listener) DeleteWatch(parentDir string, eventTypes EventType) error {
 	if l.entireMount {
 		return os.ErrInvalid
 	}
-	return l.fanotifyMark(parentDir, unix.FAN_MARK_REMOVE, uint64(eventTypes|unix.FAN_EVENT_ON_CHILD), false)
+	return l.fanotifyMark(parentDir, unix.FAN_MARK_REMOVE, uint64(eventTypes|unix.FAN_EVENT_ON_CHILD))
 }
 
 // ClearWatch stops watching for all event types
 func (l *Listener) ClearWatch() error {
 	if l == nil {
-		return ErrNilListener
+		panic("nil listener")
 	}
 	if err := unix.FanotifyMark(l.fd, unix.FAN_MARK_FLUSH, 0, -1, ""); err != nil {
 		return err
@@ -231,19 +286,22 @@ func (e EventType) Or(et EventType) EventType {
 // String prints event types
 func (e EventType) String() string {
 	var eventTypes = map[EventType]string{
-		unix.FAN_ACCESS:        "Access",
-		unix.FAN_MODIFY:        "Modify",
-		unix.FAN_CLOSE_WRITE:   "CloseWrite",
-		unix.FAN_CLOSE_NOWRITE: "CloseNoWrite",
-		unix.FAN_OPEN:          "Open",
-		unix.FAN_OPEN_EXEC:     "OpenExec",
-		unix.FAN_ATTRIB:        "AttribChange",
-		unix.FAN_CREATE:        "Create",
-		unix.FAN_DELETE:        "Delete",
-		unix.FAN_DELETE_SELF:   "SelfDelete",
-		unix.FAN_MOVED_FROM:    "MovedFrom",
-		unix.FAN_MOVED_TO:      "MovedTo",
-		unix.FAN_MOVE_SELF:     "SelfMove",
+		unix.FAN_ACCESS:         "Access",
+		unix.FAN_MODIFY:         "Modify",
+		unix.FAN_CLOSE_WRITE:    "CloseWrite",
+		unix.FAN_CLOSE_NOWRITE:  "CloseNoWrite",
+		unix.FAN_OPEN:           "Open",
+		unix.FAN_OPEN_EXEC:      "OpenExec",
+		unix.FAN_ATTRIB:         "AttribChange",
+		unix.FAN_CREATE:         "Create",
+		unix.FAN_DELETE:         "Delete",
+		unix.FAN_DELETE_SELF:    "SelfDelete",
+		unix.FAN_MOVED_FROM:     "MovedFrom",
+		unix.FAN_MOVED_TO:       "MovedTo",
+		unix.FAN_MOVE_SELF:      "SelfMove",
+		unix.FAN_OPEN_PERM:      "PermissionToOpen",
+		unix.FAN_OPEN_EXEC_PERM: "PermissionToExecute",
+		unix.FAN_ACCESS_PERM:    "PermissionToAccess",
 	}
 	var eventTypeList []string
 	for k, v := range eventTypes {
diff --git a/fanotify_event.go b/fanotify_event.go
index 0ae9f90..6d5f248 100644
--- a/fanotify_event.go
+++ b/fanotify_event.go
@@ -93,12 +93,31 @@ func flagsValid(flags uint) error {
 	return nil
 }
 
-func fanotifyMarkMaskValid(mask uint64) error {
+func isFanotifyMarkMaskValid(flags uint, mask uint64) error {
 	isSet := func(n, k uint64) bool {
 		return n&k == k
 	}
-	if isSet(mask, unix.FAN_MARK_MOUNT) && (isSet(mask, unix.FAN_CREATE) || isSet(mask, unix.FAN_ATTRIB) || isSet(mask, unix.FAN_MOVE) || isSet(mask, unix.FAN_DELETE_SELF)) {
-		return errors.New("mountpoint cannot be watched for create, attrib, move or delete self event types")
+	if isSet(uint64(flags), unix.FAN_MARK_MOUNT) {
+		if isSet(mask, unix.FAN_CREATE) ||
+			isSet(mask, unix.FAN_ATTRIB) ||
+			isSet(mask, unix.FAN_MOVE) ||
+			isSet(mask, unix.FAN_DELETE_SELF) ||
+			isSet(mask, unix.FAN_DELETE) {
+			return errors.New("mountpoint cannot be watched for create, attrib, move or delete self event types")
+		}
+	}
+	return nil
+}
+
+func checkMask(mask uint64, validEventTypes []EventType) error {
+	flags := mask
+	for _, v := range validEventTypes {
+		if flags&uint64(v) == uint64(v) {
+			flags = flags ^ uint64(v)
+		}
+	}
+	if flags != 0 {
+		return ErrInvalidFlagCombination
 	}
 	return nil
 }
@@ -191,7 +210,8 @@ func fanotifyEventOK(meta *unix.FanotifyEventMetadata, n int) bool {
 		int(meta.Event_len) <= n)
 }
 
-func newListener(mountpointPath string, entireMount bool) (*Listener, error) {
+// permissionType is ignored when isNotificationListener is true.
+func newListener(mountpointPath string, entireMount bool, notificationOnly bool, permissionType PermissionType) (*Listener, error) {
 
 	var flags, eventFlags uint
 
@@ -199,25 +219,37 @@ func newListener(mountpointPath string, entireMount bool) (*Listener, error) {
 	if err != nil {
 		return nil, err
 	}
-	switch {
-	case maj < 5:
-		flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
-	case maj == 5:
-		if min < 1 {
-			flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
-		}
-		if min >= 1 && min < 9 {
-			flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_FID
+	if !notificationOnly {
+		// permission + notification events; cannot have FID with this.
+		switch permissionType {
+		case PreContent:
+			flags = unix.FAN_CLASS_PRE_CONTENT | unix.FAN_CLOEXEC
+		case PostContent:
+			flags = unix.FAN_CLASS_CONTENT | unix.FAN_CLOEXEC
+		default:
+			return nil, os.ErrInvalid
 		}
-		if min >= 9 {
+	} else {
+		switch {
+		case maj < 5:
+			flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
+		case maj == 5:
+			if min < 1 {
+				flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
+			}
+			if min >= 1 && min < 9 {
+				flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_FID
+			}
+			if min >= 9 {
+				flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_DIR_FID | unix.FAN_REPORT_NAME
+			}
+		case maj > 5:
 			flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_DIR_FID | unix.FAN_REPORT_NAME
 		}
-	case maj > 5:
-		flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC | unix.FAN_REPORT_DIR_FID | unix.FAN_REPORT_NAME
-	}
-	// FAN_MARK_MOUNT cannot be specified with FAN_REPORT_FID, FAN_REPORT_DIR_FID, FAN_REPORT_NAME
-	if entireMount {
-		flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
+		// FAN_MARK_MOUNT cannot be specified with FAN_REPORT_FID, FAN_REPORT_DIR_FID, FAN_REPORT_NAME
+		if entireMount {
+			flags = unix.FAN_CLASS_NOTIF | unix.FAN_CLOEXEC
+		}
 	}
 	eventFlags = unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC
 	if err := flagsValid(flags); err != nil {
@@ -232,7 +264,7 @@ func newListener(mountpointPath string, entireMount bool) (*Listener, error) {
 	}
 	mountpoint, err := os.Open(mountpointPath)
 	if err != nil {
-		return nil, fmt.Errorf("error opening mountpoint %s: %w", mountpointPath, err)
+		return nil, fmt.Errorf("error opening mount point %s: %w", mountpointPath, err)
 	}
 	r, w, err := os.Pipe()
 	if err != nil {
@@ -253,27 +285,30 @@ func newListener(mountpointPath string, entireMount bool) (*Listener, error) {
 		kernelMajorVersion: maj,
 		kernelMinorVersion: min,
 		entireMount:        entireMount,
+		notificationOnly:   notificationOnly,
 		watches:            make(map[string]bool),
 		stopper: struct {
 			r *os.File
 			w *os.File
 		}{r, w},
-		Events: make(chan Event, 4096),
+		Events:           make(chan Event, 4096),
+		PermissionEvents: make(chan Event, 4096),
 	}
 	return listener, nil
 }
 
-func (l *Listener) fanotifyMark(path string, flags uint, mask uint64, remove bool) error {
-	skip := true
+func (l *Listener) fanotifyMark(path string, flags uint, mask uint64) error {
 	if l == nil {
-		return ErrNilListener
+		panic("nil listener")
 	}
+	skip := true
 	if !fanotifyMarkFlagsKernelSupport(mask, l.kernelMajorVersion, l.kernelMinorVersion) {
 		panic("some of the mark mask combinations specified are not supported on the current kernel; refer to the documentation")
 	}
-	if err := fanotifyMarkMaskValid(mask); err != nil {
+	if err := isFanotifyMarkMaskValid(flags, mask); err != nil {
 		return fmt.Errorf("%v: %w", err, ErrInvalidFlagCombination)
 	}
+	remove := flags&unix.FAN_MARK_REMOVE == unix.FAN_MARK_REMOVE
 	_, found := l.watches[path]
 	if found {
 		if remove {
@@ -384,7 +419,13 @@ func (l *Listener) readEvents() error {
 					EventTypes: EventType(mask),
 					Pid:        int(metadata.Pid),
 				}
-				l.Events <- event
+				if mask&unix.FAN_ACCESS_PERM == unix.FAN_ACCESS_PERM ||
+					mask&unix.FAN_OPEN_PERM == unix.FAN_OPEN_PERM ||
+					mask&unix.FAN_OPEN_EXEC_PERM == unix.FAN_OPEN_EXEC_PERM {
+					l.PermissionEvents <- event
+				} else {
+					l.Events <- event
+				}
 				i += int(metadata.Event_len)
 				n -= int(metadata.Event_len)
 				metadata = (*unix.FanotifyEventMetadata)(unsafe.Pointer(&buf[i]))
@@ -433,6 +474,8 @@ func (l *Listener) readEvents() error {
 					EventTypes: EventType(mask),
 					Pid:        int(metadata.Pid),
 				}
+				// As of the kernel release (6.0) permission events cannot have FID flags.
+				// So the event here is always a notification event
 				l.Events <- event
 				i += int(metadata.Event_len)
 				n -= int(metadata.Event_len)
diff --git a/fanotify_event_types.go b/fanotify_event_types.go
index 9078140..d854b95 100644
--- a/fanotify_event_types.go
+++ b/fanotify_event_types.go
@@ -22,15 +22,9 @@ const (
 	FileClosed EventType = unix.FAN_CLOSE_WRITE | unix.FAN_CLOSE_NOWRITE
 
 	// FileOpened event when a file is opened
-	// BUG Using FileOpened flag with any OrDirectory event types
-	// causes an event flood and complete stoppage of events. The flag
-	// can be used with other file only flags or by itself
-	// without any errors/issues.
 	FileOpened EventType = unix.FAN_OPEN
 
 	// FileOrDirectoryOpened event when a file or directory is opened
-	// BUG Using FileOrDirectoryOpened causes an event flood and complete
-	// stoppage of events. The flag by itself without any errors/issues.
 	FileOrDirectoryOpened EventType = unix.FAN_OPEN | unix.FAN_ONDIR
 
 	// FileOpenedForExec event when a file is opened with the intent to be executed.
@@ -93,4 +87,14 @@ const (
 	// WatchedFileOrDirectoryMoved event when a watched file or directory has moved
 	// Requires Linux kernel 5.1 or later (requires FID)
 	WatchedFileOrDirectoryMoved EventType = unix.FAN_MOVE_SELF | unix.FAN_ONDIR
+
+	// FileOpenPermission event when a permission to open a file or directory is requested
+	FileOpenPermission EventType = unix.FAN_OPEN_PERM
+
+	// FileOpenToExecutePermission event when a permission to open a file for
+	// execution is requested
+	FileOpenToExecutePermission EventType = unix.FAN_OPEN_EXEC_PERM
+
+	// FileAccessPermission event when a permission to read a file or directory is requested
+	FileAccessPermission EventType = unix.FAN_ACCESS_PERM
 )
diff --git a/fanotify_test.go b/fanotify_test.go
index 31f5887..589fce4 100644
--- a/fanotify_test.go
+++ b/fanotify_test.go
@@ -39,7 +39,7 @@ func runAsCmd(args ...string) (int, error) {
 }
 
 func TestWithCapSysAdmFanotifyFileAccessed(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -67,7 +67,7 @@ func TestWithCapSysAdmFanotifyFileAccessed(t *testing.T) {
 }
 
 func TestWithCapSysAdmFanotifyFileModified(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -95,7 +95,7 @@ func TestWithCapSysAdmFanotifyFileModified(t *testing.T) {
 }
 
 func TestWithCapSysAdmFanotifyFileClosed(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -123,7 +123,7 @@ func TestWithCapSysAdmFanotifyFileClosed(t *testing.T) {
 }
 
 func TestWithCapSysAdmFanotifyFileOpen(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -151,7 +151,7 @@ func TestWithCapSysAdmFanotifyFileOpen(t *testing.T) {
 }
 
 func TestWithCapSysAdmFanotifyFileOrDirectoryOpen(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -175,7 +175,7 @@ func TestWithCapSysAdmFanotifyFileOrDirectoryOpen(t *testing.T) {
 }
 
 func TestWithCapSysAdmFanotifyFileOpenForExec(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -208,7 +208,7 @@ exit 0
 }
 
 func TestWithCapSysAdmFanotifyFileAttribChanged(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -241,7 +241,7 @@ exit 0
 }
 
 func TestWithCapSysAdmFanotifyFileCreated(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -265,7 +265,7 @@ func TestWithCapSysAdmFanotifyFileCreated(t *testing.T) {
 }
 
 func TestWithCapSysAdmFanotifyFileOrDirectoryCreated(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	watchDir := t.TempDir()
@@ -290,7 +290,7 @@ func TestWithCapSysAdmFanotifyFileOrDirectoryCreated(t *testing.T) {
 
 func TestWithCapSysAdmFanotifyFileDeleted(t *testing.T) {
 
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 
@@ -319,7 +319,7 @@ func TestWithCapSysAdmFanotifyFileDeleted(t *testing.T) {
 
 func TestWithCapSysAdmFanotifyFileOrDirectoryDeleted(t *testing.T) {
 
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 
@@ -355,7 +355,7 @@ func TestEventTypes(t *testing.T) {
 }
 
 func TestMultipleEvents(t *testing.T) {
-	l, err := NewListener("/", false)
+	l, err := NewListener("/", false, PermissionNone)
 	assert.Nil(t, err)
 	assert.NotNil(t, l)
 	go l.Start()
@@ -413,7 +413,7 @@ func TestMultipleEvents(t *testing.T) {
 // FileCreated and FileClosed combination does not raise any events
 func TestWithCapSysAdmMarkCreateCloseBug(t *testing.T) {
 	if *bug {
-		l, err := NewListener("/", false)
+		l, err := NewListener("/", false, PermissionNone)
 		assert.Nil(t, err)
 		assert.NotNil(t, l)
 		go l.Start()
@@ -461,7 +461,7 @@ func TestWithCapSysAdmMarkFileOrDirectoryOpenedBug(t *testing.T) {
 		assert.Nil(t, err)
 
 		// start the listener
-		l, err := NewListener("/", false)
+		l, err := NewListener("/", false, PermissionNone)
 		assert.Nil(t, err)
 		assert.NotNil(t, l)
 		go l.Start()
