nvme: fix possible hang when removing a controller during error recovery
[linux-block.git] / fs / fhandle.c
index f2bc27d1975e14bd45da242fe25b083b32b2e015..6ea8d35a9382ace3fac22b89c818c74f0f123c34 100644 (file)
@@ -16,7 +16,7 @@
 
 static long do_sys_name_to_handle(const struct path *path,
                                  struct file_handle __user *ufh,
-                                 int __user *mnt_id)
+                                 int __user *mnt_id, int fh_flags)
 {
        long retval;
        struct file_handle f_handle;
@@ -24,11 +24,14 @@ static long do_sys_name_to_handle(const struct path *path,
        struct file_handle *handle = NULL;
 
        /*
-        * We need to make sure whether the file system
-        * support decoding of the file handle
+        * We need to make sure whether the file system support decoding of
+        * the file handle if decodeable file handle was requested.
+        * Otherwise, even empty export_operations are sufficient to opt-in
+        * to encoding FIDs.
         */
        if (!path->dentry->d_sb->s_export_op ||
-           !path->dentry->d_sb->s_export_op->fh_to_dentry)
+           (!(fh_flags & EXPORT_FH_FID) &&
+            !path->dentry->d_sb->s_export_op->fh_to_dentry))
                return -EOPNOTSUPP;
 
        if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
@@ -45,27 +48,28 @@ static long do_sys_name_to_handle(const struct path *path,
        /* convert handle size to multiple of sizeof(u32) */
        handle_dwords = f_handle.handle_bytes >> 2;
 
-       /* we ask for a non connected handle */
+       /* we ask for a non connectable maybe decodeable file handle */
        retval = exportfs_encode_fh(path->dentry,
                                    (struct fid *)handle->f_handle,
-                                   &handle_dwords,  0);
+                                   &handle_dwords, fh_flags);
        handle->handle_type = retval;
        /* convert handle size to bytes */
        handle_bytes = handle_dwords * sizeof(u32);
        handle->handle_bytes = handle_bytes;
        if ((handle->handle_bytes > f_handle.handle_bytes) ||
-           (retval == FILEID_INVALID) || (retval == -ENOSPC)) {
+           (retval == FILEID_INVALID) || (retval < 0)) {
                /* As per old exportfs_encode_fh documentation
                 * we could return ENOSPC to indicate overflow
                 * But file system returned 255 always. So handle
                 * both the values
                 */
+               if (retval == FILEID_INVALID || retval == -ENOSPC)
+                       retval = -EOVERFLOW;
                /*
                 * set the handle size to zero so we copy only
                 * non variable part of the file_handle
                 */
                handle_bytes = 0;
-               retval = -EOVERFLOW;
        } else
                retval = 0;
        /* copy the mount id */
@@ -84,6 +88,7 @@ static long do_sys_name_to_handle(const struct path *path,
  * @handle: resulting file handle
  * @mnt_id: mount id of the file system containing the file
  * @flag: flag value to indicate whether to follow symlink or not
+ *        and whether a decodable file handle is required.
  *
  * @handle->handle_size indicate the space available to store the
  * variable part of the file handle in bytes. If there is not
@@ -96,17 +101,19 @@ SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
 {
        struct path path;
        int lookup_flags;
+       int fh_flags;
        int err;
 
-       if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
+       if (flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH | AT_HANDLE_FID))
                return -EINVAL;
 
        lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
+       fh_flags = (flag & AT_HANDLE_FID) ? EXPORT_FH_FID : 0;
        if (flag & AT_EMPTY_PATH)
                lookup_flags |= LOOKUP_EMPTY;
        err = user_path_at(dfd, name, lookup_flags, &path);
        if (!err) {
-               err = do_sys_name_to_handle(&path, handle, mnt_id);
+               err = do_sys_name_to_handle(&path, handle, mnt_id, fh_flags);
                path_put(&path);
        }
        return err;
@@ -235,7 +242,6 @@ static long do_handle_open(int mountdirfd, struct file_handle __user *ufh,
                retval =  PTR_ERR(file);
        } else {
                retval = fd;
-               fsnotify_open(file);
                fd_install(fd, file);
        }
        path_put(&path);