diff --git a/btrfs-list.c b/btrfs-list.c
index 38d7f9c..ce20593 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -57,6 +57,9 @@ struct root_info {
 	/* equal the offset of the root's key */
 	u64 root_offset;
 
+	/* flags of the root */
+	u64 flags;
+
 	/* the id of the root that references this one */
 	u64 ref_tree;
 
@@ -340,9 +343,9 @@ static struct root_info *root_tree_search(struct root_lookup *root_tree,
 }
 
 static int update_root(struct root_lookup *root_lookup,
-		       u64 root_id, u64 ref_tree, u64 root_offset, u64 dir_id,
-		       char *name, int name_len, u64 ogen, u64 gen, time_t ot,
-		       void *uuid)
+		       u64 root_id, u64 ref_tree, u64 root_offset, u64 flags,
+		       u64 dir_id, char *name, int name_len, u64 ogen, u64 gen,
+		       time_t ot, void *uuid)
 {
 	struct root_info *ri;
 
@@ -365,6 +368,8 @@ static int update_root(struct root_lookup *root_lookup,
 		ri->ref_tree = ref_tree;
 	if (root_offset)
 		ri->root_offset = root_offset;
+	if (flags)
+		ri->flags = flags;
 	if (dir_id)
 		ri->dir_id = dir_id;
 	if (gen)
@@ -396,15 +401,15 @@ static int update_root(struct root_lookup *root_lookup,
  * uuid: uuid of the root
  */
 static int add_root(struct root_lookup *root_lookup,
-		    u64 root_id, u64 ref_tree, u64 root_offset, u64 dir_id,
-		    char *name, int name_len, u64 ogen, u64 gen, time_t ot,
-		    void *uuid)
+		    u64 root_id, u64 ref_tree, u64 root_offset, u64 flags,
+		    u64 dir_id, char *name, int name_len, u64 ogen, u64 gen,
+		    time_t ot, void *uuid)
 {
 	struct root_info *ri;
 	int ret;
 
-	ret = update_root(root_lookup, root_id, ref_tree, root_offset, dir_id,
-			  name, name_len, ogen, gen, ot, uuid);
+	ret = update_root(root_lookup, root_id, ref_tree, root_offset, flags,
+			  dir_id, name, name_len, ogen, gen, ot, uuid);
 	if (!ret)
 		return 0;
 
@@ -431,6 +436,8 @@ static int add_root(struct root_lookup *root_lookup,
 		ri->dir_id = dir_id;
 	if (root_offset)
 		ri->root_offset = root_offset;
+	if (flags)
+		ri->flags = flags;
 	if (gen)
 		ri->gen = gen;
 	if (ogen)
@@ -907,6 +914,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 	u64 dir_id;
 	u64 gen = 0;
 	u64 ogen;
+	u64 flags;
 	int i;
 	time_t t;
 	u8 uuid[BTRFS_UUID_SIZE];
@@ -962,11 +970,12 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 				dir_id = btrfs_stack_root_ref_dirid(ref);
 
 				add_root(root_lookup, sh->objectid, sh->offset,
-					 0, dir_id, name, name_len, 0, 0, 0,
+					 0, 0, dir_id, name, name_len, 0, 0, 0,
 					 NULL);
 			} else if (sh->type == BTRFS_ROOT_ITEM_KEY) {
 				ri = (struct btrfs_root_item *)(args.buf + off);
 				gen = btrfs_root_generation(ri);
+				flags = btrfs_root_flags(ri);
 				if(sh->len == sizeof(struct btrfs_root_item)) {
 					t = ri->otime.sec;
 					ogen = btrfs_root_otransid(ri);
@@ -978,8 +987,8 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup)
 				}
 
 				add_root(root_lookup, sh->objectid, 0,
-					 sh->offset, 0, NULL, 0, ogen, gen, t,
-					 uuid);
+					 sh->offset, flags, 0, NULL, 0, ogen,
+					 gen, t, uuid);
 			}
 
 			off += sh->len;
@@ -1024,9 +1033,17 @@ static int filter_snapshot(struct root_info *ri, void *arg)
 	return !!ri->root_offset;
 }
 
+static int filter_flags(struct root_info *ri, void *arg)
+{
+	u64 flags = *((u64 *)arg);
+
+	return ri->flags & flags;
+}
+
 static btrfs_list_filter_func all_filter_funcs[] = {
 	[BTRFS_LIST_FILTER_ROOTID]		= filter_by_rootid,
 	[BTRFS_LIST_FILTER_SNAPSHOT_ONLY]	= filter_snapshot,
+	[BTRFS_LIST_FILTER_FLAGS]		= filter_flags,
 };
 
 void btrfs_list_init_filters(struct btrfs_list_filter filters[], int nfilters)
diff --git a/btrfs-list.h b/btrfs-list.h
index 56d6a26..5eedfc3 100644
--- a/btrfs-list.h
+++ b/btrfs-list.h
@@ -47,6 +47,7 @@ enum btrfs_list_column_enum {
 enum btrfs_list_filter_enum {
 	BTRFS_LIST_FILTER_ROOTID,
 	BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
+	BTRFS_LIST_FILTER_FLAGS,
 	BTRFS_LIST_FILTER_MAX,
 };
 
diff --git a/cmds-subvolume.c b/cmds-subvolume.c
index f29894c..19e7275 100644
--- a/cmds-subvolume.c
+++ b/cmds-subvolume.c
@@ -259,13 +259,14 @@ static int cmd_subvol_delete(int argc, char **argv)
 }
 
 static const char * const cmd_subvol_list_usage[] = {
-	"btrfs subvolume list [-pu] [-s 0|1] <path>",
+	"btrfs subvolume list [-pur] [-s 0|1] <path>",
 	"List subvolumes (and snapshots)",
 	"",
 	"-p           print parent ID",
 	"-u           print the uuid of subvolumes (and snapshots)",
 	"-s value     list snapshots with generation in ascending/descending order",
 	"             (1: ascending, 0: descending)",
+	"-r           list readonly subvolumes(including snapshots)",
 	NULL
 };
 
@@ -273,6 +274,7 @@ static int cmd_subvol_list(int argc, char **argv)
 {
 	struct btrfs_list_filter filters[BTRFS_LIST_FILTER_MAX];
 	struct btrfs_list_comparer comps[BTRFS_LIST_COMP_MAX];
+	u64 flags = 0;
 	int fd;
 	int ret;
 	int order;
@@ -284,7 +286,7 @@ static int cmd_subvol_list(int argc, char **argv)
 
 	optind = 1;
 	while(1) {
-		int c = getopt(argc, argv, "ps:u");
+		int c = getopt(argc, argv, "ps:ur");
 		if (c < 0)
 			break;
 
@@ -307,11 +309,20 @@ static int cmd_subvol_list(int argc, char **argv)
 		case 'u':
 			btrfs_list_setup_print_column(BTRFS_LIST_UUID);
 			break;
+		case 'r':
+			flags |= BTRFS_ROOT_SUBVOL_RDONLY;
+			break;
 		default:
 			usage(cmd_subvol_list_usage);
 		}
 	}
 
+	if (flags)
+		btrfs_list_setup_filter(filters, BTRFS_LIST_FILTER_MAX,
+					filter_index++,
+					BTRFS_LIST_FILTER_FLAGS,
+					(void *)&flags);
+
 	if (check_argc_exact(argc - optind, 1))
 		usage(cmd_subvol_list_usage);
 
diff --git a/ctree.h b/ctree.h
index 7f55229..ac31efe 100644
--- a/ctree.h
+++ b/ctree.h
@@ -139,6 +139,8 @@ static int btrfs_csum_sizes[] = { 4, 0 };
 #define BTRFS_FT_XATTR		8
 #define BTRFS_FT_MAX		9
 
+#define BTRFS_ROOT_SUBVOL_RDONLY	(1ULL << 0)
+
 /*
  * the key defines the order in the tree, and so it also defines (optimal)
  * block layout.  objectid corresonds to the inode number.  The flags
