return info ? fanotify_info_dir_fh_len(info) : 0;
 }
 
+static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event)
+{
+       struct fanotify_info *info = fanotify_event_info(event);
+
+       return info ? fanotify_info_dir2_fh_len(info) : 0;
+}
+
 static inline bool fanotify_event_has_object_fh(struct fanotify_event *event)
 {
        /* For error events, even zeroed fh are reported. */
        return fanotify_event_dir_fh_len(event) > 0;
 }
 
+static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event)
+{
+       return fanotify_event_dir2_fh_len(event) > 0;
+}
+
+static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event)
+{
+       return fanotify_event_has_dir_fh(event) ||
+               fanotify_event_has_dir2_fh(event);
+}
+
 struct fanotify_path_event {
        struct fanotify_event fae;
        struct path path;
 
                       FANOTIFY_EVENT_ALIGN);
 }
 
+/* FAN_RENAME may have one or two dir+name info records */
+static int fanotify_dir_name_info_len(struct fanotify_event *event)
+{
+       struct fanotify_info *info = fanotify_event_info(event);
+       int dir_fh_len = fanotify_event_dir_fh_len(event);
+       int dir2_fh_len = fanotify_event_dir2_fh_len(event);
+       int info_len = 0;
+
+       if (dir_fh_len)
+               info_len += fanotify_fid_info_len(dir_fh_len,
+                                                 info->name_len);
+       if (dir2_fh_len)
+               info_len += fanotify_fid_info_len(dir2_fh_len,
+                                                 info->name2_len);
+
+       return info_len;
+}
+
 static size_t fanotify_event_len(unsigned int info_mode,
                                 struct fanotify_event *event)
 {
        size_t event_len = FAN_EVENT_METADATA_LEN;
        struct fanotify_info *info;
-       int dir_fh_len;
        int fh_len;
        int dot_len = 0;
 
 
        info = fanotify_event_info(event);
 
-       if (fanotify_event_has_dir_fh(event)) {
-               dir_fh_len = fanotify_event_dir_fh_len(event);
-               event_len += fanotify_fid_info_len(dir_fh_len, info->name_len);
+       if (fanotify_event_has_any_dir_fh(event)) {
+               event_len += fanotify_dir_name_info_len(event);
        } else if ((info_mode & FAN_REPORT_NAME) &&
                   (event->mask & FAN_ONDIR)) {
                /*
                        return -EFAULT;
                break;
        case FAN_EVENT_INFO_TYPE_DFID_NAME:
+       case FAN_EVENT_INFO_TYPE_OLD_DFID_NAME:
+       case FAN_EVENT_INFO_TYPE_NEW_DFID_NAME:
                if (WARN_ON_ONCE(!name || !name_len))
                        return -EFAULT;
                break;
        unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD;
 
        /*
-        * Event info records order is as follows: dir fid + name, child fid.
+        * Event info records order is as follows:
+        * 1. dir fid + name
+        * 2. (optional) new dir fid + new name
+        * 3. (optional) child fid
         */
        if (fanotify_event_has_dir_fh(event)) {
                info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME :
                                             FAN_EVENT_INFO_TYPE_DFID;
+
+               /* FAN_RENAME uses special info types */
+               if (event->mask & FAN_RENAME)
+                       info_type = FAN_EVENT_INFO_TYPE_OLD_DFID_NAME;
+
                ret = copy_fid_info_to_user(fanotify_event_fsid(event),
                                            fanotify_info_dir_fh(info),
                                            info_type,
                total_bytes += ret;
        }
 
+       /* New dir fid+name may be reported in addition to old dir fid+name */
+       if (fanotify_event_has_dir2_fh(event)) {
+               info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
+               ret = copy_fid_info_to_user(fanotify_event_fsid(event),
+                                           fanotify_info_dir2_fh(info),
+                                           info_type,
+                                           fanotify_info_name2(info),
+                                           info->name2_len, buf, count);
+               if (ret < 0)
+                       return ret;
+
+               buf += ret;
+               count -= ret;
+               total_bytes += ret;
+       }
+
        if (fanotify_event_has_object_fh(event)) {
                const char *dot = NULL;
                int dot_len = 0;