From: Ben Hutchings <ben@decadent.org.uk>
Date: Sat, 14 Dec 2013 17:14:39 +0000
Subject: firmware_class: Return specific errors from file read
Forwarded: no

Currently several failure cases are not distinguished and are
incorrectly reported as -EINVAL or -ENOENT.

Change fw_file_size() to return an error code on failure and
adjust fw_read_file_contents() and fw_get_filesystem_firmware()

Change _request_firmware() to return the error code from
fw_get_filesystem_firmware() if CONFIG_FW_LOADER_USER_HELPER is not
enabled.  (If it is enabled and also fails, unfortunately we can't
tell why.)

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -298,7 +298,7 @@ static int fw_read_file_contents(struct
 	int rc;
 
 	if (!S_ISREG(file_inode(file)->i_mode))
-		return -EINVAL;
+		return -ENOTTY;
 	size = i_size_read(file_inode(file));
 	if (size <= 0)
 		return -EINVAL;
@@ -307,7 +307,7 @@ static int fw_read_file_contents(struct
 		return -ENOMEM;
 	rc = kernel_read(file, 0, buf, size);
 	if (rc != size) {
-		if (rc > 0)
+		if (rc >= 0)
 			rc = -EIO;
 		goto fail;
 	}
@@ -348,8 +348,10 @@ static int fw_get_filesystem_firmware(st
 		}
 
 		file = filp_open(path, O_RDONLY, 0);
-		if (IS_ERR(file))
+		if (IS_ERR(file)) {
+			rc = PTR_ERR(file);
 			continue;
+		}
 		rc = fw_read_file_contents(file, buf);
 		fput(file);
 		if (rc)
@@ -994,13 +996,6 @@ static void kill_requests_without_uevent
 #endif
 
 #else /* CONFIG_FW_LOADER_USER_HELPER */
-static inline int
-fw_load_from_user_helper(struct firmware *firmware, const char *name,
-			 struct device *device, unsigned int opt_flags,
-			 long timeout)
-{
-	return -ENOENT;
-}
 
 /* No abort during direct loading */
 #define is_fw_load_aborted(buf) false
@@ -1152,6 +1147,7 @@ _request_firmware(const struct firmware
 	}
 
 	ret = fw_get_filesystem_firmware(device, fw->priv);
+#ifdef CONFIG_FW_LOADER_USER_HELPER
 	if (ret) {
 		if (!(opt_flags & FW_OPT_NO_WARN))
 			dev_warn(device,
@@ -1163,6 +1159,7 @@ _request_firmware(const struct firmware
 						       opt_flags, timeout);
 		}
 	}
+#endif
 
 	if (!ret)
 		ret = assign_firmware_buf(fw, device, opt_flags);
