浏览代码

btrfs: add varargs to btrfs_error

 btrfs currently handles most errors with BUG_ON. This patch is a work-in-
 progress but aims to handle most errors other than internal logic
 errors and ENOMEM more gracefully.

 This iteration prevents most crashes but can run into lockups with
 the page lock on occasion when the timing "works out."

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Jeff Mahoney 13 年之前
父节点
当前提交
4da3511342
共有 2 个文件被更改,包括 66 次插入9 次删除
  1. 10 2
      fs/btrfs/ctree.h
  2. 56 7
      fs/btrfs/super.c

+ 10 - 2
fs/btrfs/ctree.h

@@ -2964,13 +2964,21 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
 /* super.c */
 /* super.c */
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_parse_options(struct btrfs_root *root, char *options);
 int btrfs_sync_fs(struct super_block *sb, int wait);
 int btrfs_sync_fs(struct super_block *sb, int wait);
+void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...);
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
-		     unsigned int line, int errno);
+		     unsigned int line, int errno, const char *fmt, ...);
 
 
 #define btrfs_std_error(fs_info, errno)				\
 #define btrfs_std_error(fs_info, errno)				\
 do {								\
 do {								\
 	if ((errno))						\
 	if ((errno))						\
-		__btrfs_std_error((fs_info), __func__, __LINE__, (errno));\
+		__btrfs_std_error((fs_info), __func__,		\
+				   __LINE__, (errno), NULL);	\
+} while (0)
+
+#define btrfs_error(fs_info, errno, fmt, args...)		\
+do {								\
+	__btrfs_std_error((fs_info), __func__, __LINE__,	\
+			  (errno), fmt, ##args);		\
 } while (0)
 } while (0)
 
 
 void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
 void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,

+ 56 - 7
fs/btrfs/super.c

@@ -127,25 +127,74 @@ static void btrfs_handle_error(struct btrfs_fs_info *fs_info)
  * invokes the approciate error response.
  * invokes the approciate error response.
  */
  */
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
-		     unsigned int line, int errno)
+		       unsigned int line, int errno, const char *fmt, ...)
 {
 {
 	struct super_block *sb = fs_info->sb;
 	struct super_block *sb = fs_info->sb;
 	char nbuf[16];
 	char nbuf[16];
 	const char *errstr;
 	const char *errstr;
+	va_list args;
+	va_start(args, fmt);
 
 
 	/*
 	/*
 	 * Special case: if the error is EROFS, and we're already
 	 * Special case: if the error is EROFS, and we're already
 	 * under MS_RDONLY, then it is safe here.
 	 * under MS_RDONLY, then it is safe here.
 	 */
 	 */
 	if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
 	if (errno == -EROFS && (sb->s_flags & MS_RDONLY))
-		return;
+  		return;
 
 
-	errstr = btrfs_decode_error(fs_info, errno, nbuf);
-	printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n",
-		sb->s_id, function, line, errstr);
-	save_error_info(fs_info);
+  	errstr = btrfs_decode_error(fs_info, errno, nbuf);
+	if (fmt) {
+		struct va_format vaf = {
+			.fmt = fmt,
+			.va = &args,
+		};
+
+		printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s (%pV)\n",
+			sb->s_id, function, line, errstr, &vaf);
+	} else {
+		printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: %s\n",
+			sb->s_id, function, line, errstr);
+	}
+
+	/* Don't go through full error handling during mount */
+	if (sb->s_flags & MS_BORN) {
+		save_error_info(fs_info);
+		btrfs_handle_error(fs_info);
+	}
+	va_end(args);
+}
 
 
-	btrfs_handle_error(fs_info);
+const char *logtypes[] = {
+	"emergency",
+	"alert",
+	"critical",
+	"error",
+	"warning",
+	"notice",
+	"info",
+	"debug",
+};
+
+void btrfs_printk(struct btrfs_fs_info *fs_info, const char *fmt, ...)
+{
+	struct super_block *sb = fs_info->sb;
+	char lvl[4];
+	struct va_format vaf;
+	va_list args;
+	const char *type = logtypes[4];
+
+	va_start(args, fmt);
+
+	if (fmt[0] == '<' && isdigit(fmt[1]) && fmt[2] == '>') {
+		strncpy(lvl, fmt, 3);
+		fmt += 3;
+		type = logtypes[fmt[1] - '0'];
+	} else
+		*lvl = '\0';
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+	printk("%sBTRFS %s (device %s): %pV", lvl, type, sb->s_id, &vaf);
 }
 }
 
 
 /*
 /*