diff --git a/.gitignore b/.gitignore
index 849e799..ba01e7f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1 @@
-SOURCES/targetcli-fb-2.1.fb46.tar.gz
+SOURCES/targetcli-fb-2.1.fb49.tar.gz
diff --git a/.targetcli.metadata b/.targetcli.metadata
index 8fae95d..52a4911 100644
--- a/.targetcli.metadata
+++ b/.targetcli.metadata
@@ -1 +1 @@
-cbfc05ef7baac08165fdb17efe26081eb9850363 SOURCES/targetcli-fb-2.1.fb46.tar.gz
+f55bb874f9644991a042ee83f25c14d44a86d2db SOURCES/targetcli-fb-2.1.fb49.tar.gz
diff --git a/SOURCES/0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch b/SOURCES/0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch
deleted file mode 100644
index ecefe7e..0000000
--- a/SOURCES/0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 8011ea6a741d494c145b4906f7a7865c8b74c6a7 Mon Sep 17 00:00:00 2001
-From: Christian Seiler <christian@iwakd.de>
-Date: Thu, 23 Mar 2017 19:36:18 +0100
-Subject: [PATCH] Properly detect errors when writing backup files. (Closes:
- #80) (#81)
-
-* Properly detect errors when writing backup files. (Closes: #80)
-
-If the backup directory does not exist, properly detect that and show a
-warning message to the user, so that they don't think that their
-configuration was backed up, when it fact wasn't.
-
-Additionally, try to automatically create the backup directory if it
-does not exist.
-
-Signed-off-by: Christian Seiler <christian@iwakd.de>
-
-* Don't automatically create backup directory if it doesn't exist.
-
-After discussion on the issue tracker, it was decided to not
-auto-create the backup-directory if it doesn't exist yet.
-
-If the directory doesn't exist, the user will now see the warning.
-
-Signed-off-by: Christian Seiler <christian@iwakd.de>
----
- targetcli/ui_root.py | 28 ++++++++++++++++++----------
- 1 file changed, 18 insertions(+), 10 deletions(-)
-
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index 2d8989c..c3a8483 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -75,17 +75,25 @@ class UIRoot(UINode):
-             backup_name = "saveconfig-" + \
-                 datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json"
-             backupfile = backup_dir + "/" + backup_name
--            with ignored(IOError):
-+            backup_error = None
-+            try:
-                 shutil.copy(savefile, backupfile)
--
--            # Kill excess backups
--            backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
--            files_to_unlink = list(reversed(backups))[kept_backups:]
--            for f in files_to_unlink:
--                os.unlink(f)
--
--            self.shell.log.info("Last %d configs saved in %s." % \
--                                    (kept_backups, backup_dir))
-+            except IOError as ioe:
-+                backup_error = ioe.strerror or "Unknown error"
-+
-+            if backup_error == None:
-+                # Kill excess backups
-+                backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
-+                files_to_unlink = list(reversed(backups))[kept_backups:]
-+                for f in files_to_unlink:
-+                    with ignored(IOError):
-+                        os.unlink(f)
-+
-+                self.shell.log.info("Last %d configs saved in %s." % \
-+                                        (kept_backups, backup_dir))
-+            else:
-+                self.shell.log.warning("Could not create backup file %s: %s." % \
-+                                           (backupfile, backup_error))
- 
-         self.rtsroot.save_to_file(savefile)
- 
--- 
-1.8.3.1
-
diff --git a/SOURCES/0002-Read-number-of-backup-files-to-keep-from-file.patch b/SOURCES/0002-Read-number-of-backup-files-to-keep-from-file.patch
deleted file mode 100644
index 6c591e3..0000000
--- a/SOURCES/0002-Read-number-of-backup-files-to-keep-from-file.patch
+++ /dev/null
@@ -1,52 +0,0 @@
-From bf0fb387cef89bb0dc51cf1740ab73abf549c38e Mon Sep 17 00:00:00 2001
-From: Taylor Jakobson <tjakobs@us.ibm.com>
-Date: Mon, 23 Oct 2017 14:26:03 -0500
-Subject: [PATCH] Read number of backup files to keep from file
-
-Use /etc/target/targetcli.conf file to store universal configurations
-that are the same for all users.
-Configuration file has format of:
-    key = value
----
- targetcli/ui_root.py | 11 ++++++++++-
- 1 file changed, 10 insertions(+), 1 deletion(-)
-
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index c3a8483..8bc8521 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -20,6 +20,7 @@ under the License.
- from datetime import datetime
- from glob import glob
- import os
-+import re
- import shutil
- import stat
- 
-@@ -32,7 +33,8 @@ from .ui_node import UINode
- from .ui_target import UIFabricModule
- 
- default_save_file = "/etc/target/saveconfig.json"
--kept_backups = 10
-+universal_prefs_file = "/etc/target/targetcli.conf"
-+default_kept_backups = 10
- 
- class UIRoot(UINode):
-     '''
-@@ -83,6 +85,13 @@ class UIRoot(UINode):
- 
-             if backup_error == None:
-                 # Kill excess backups
-+                try:
-+                    with open(universal_prefs_file) as prefs:
-+                        backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)]
-+                        kept_backups = int(backups[0].split('=')[1].strip())
-+                except:
-+                    kept_backups = default_kept_backups
-+
-                 backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
-                 files_to_unlink = list(reversed(backups))[kept_backups:]
-                 for f in files_to_unlink:
--- 
-1.8.3.1
-
diff --git a/SOURCES/0003-config-defend-on-etc-target-backup-directory.patch b/SOURCES/0003-config-defend-on-etc-target-backup-directory.patch
deleted file mode 100644
index 837f9af..0000000
--- a/SOURCES/0003-config-defend-on-etc-target-backup-directory.patch
+++ /dev/null
@@ -1,99 +0,0 @@
-From 6349a75bd71f2f15c3acd89588321524c94676e8 Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Fri, 15 Dec 2017 15:16:28 +0530
-Subject: [PATCH] config: defend on '/etc/target/backup' directory
-
-Currently we do not create '/etc/target/backup/' while we expect the directory
-to be presented by package (rpm).
-
-If for some reason '/etc/target/backup' is not available, say may be a
-unintentional deletion or use of targetcli which is compiled from source,
-we see below errors on up on saveconfig command,
-
-Case 1: No '/etc/target/backup/' dir
-
-$ targetcli / saveconfig
-Could not create backup file /etc/target/backup/saveconfig-20171215-15:26:48.json: No such file or directory.
-Configuration saved to /etc/target/saveconfig.json
-
-Case 2: No '/etc/target/' dir
-
-$ targetcli / saveconfig
-Could not create backup file /etc/target/backup/saveconfig-20171215-15:27:42.json: No such file or directory.
-[Errno 2] No such file or directory: '/etc/target/saveconfig.json.temp'
-
-This patch tries to create '/etc/target/backup' directory tree in case if it
-is absent.
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- targetcli/ui_root.py | 50 +++++++++++++++++++++++++++++---------------------
- 1 file changed, 29 insertions(+), 21 deletions(-)
-
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index 8bc8521..33bb948 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -78,30 +78,38 @@ class UIRoot(UINode):
-                 datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json"
-             backupfile = backup_dir + "/" + backup_name
-             backup_error = None
--            try:
--                shutil.copy(savefile, backupfile)
--            except IOError as ioe:
--                backup_error = ioe.strerror or "Unknown error"
- 
--            if backup_error == None:
--                # Kill excess backups
-+            if not os.path.exists(backup_dir):
-+                try:
-+                    os.makedirs(backup_dir);
-+                except OSError as exe:
-+                    raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror))
-+
-+            if os.path.exists(savefile):
-                 try:
--                    with open(universal_prefs_file) as prefs:
--                        backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)]
--                        kept_backups = int(backups[0].split('=')[1].strip())
--                except:
--                    kept_backups = default_kept_backups
--
--                backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
--                files_to_unlink = list(reversed(backups))[kept_backups:]
--                for f in files_to_unlink:
--                    with ignored(IOError):
--                        os.unlink(f)
--
--                self.shell.log.info("Last %d configs saved in %s." % \
-+                    shutil.copy(savefile, backupfile)
-+                except IOError as ioe:
-+                    backup_error = ioe.strerror or "Unknown error"
-+
-+                if backup_error == None:
-+                    # Kill excess backups
-+                    try:
-+                        with open(universal_prefs_file) as prefs:
-+                            backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)]
-+                            kept_backups = int(backups[0].split('=')[1].strip())
-+                    except:
-+                        kept_backups = default_kept_backups
-+
-+                    backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
-+                    files_to_unlink = list(reversed(backups))[kept_backups:]
-+                    for f in files_to_unlink:
-+                        with ignored(IOError):
-+                            os.unlink(f)
-+
-+                    self.shell.log.info("Last %d configs saved in %s." % \
-                                         (kept_backups, backup_dir))
--            else:
--                self.shell.log.warning("Could not create backup file %s: %s." % \
-+                else:
-+                    self.shell.log.warning("Could not create backup file %s: %s." % \
-                                            (backupfile, backup_error))
- 
-         self.rtsroot.save_to_file(savefile)
--- 
-1.8.3.1
-
diff --git a/SOURCES/0004-config-backup-when-current-config-is-different-from-.patch b/SOURCES/0004-config-backup-when-current-config-is-different-from-.patch
deleted file mode 100644
index 69ed6cc..0000000
--- a/SOURCES/0004-config-backup-when-current-config-is-different-from-.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From 6efbd7e4c0217d1f6b46e22ec51a209439678f5a Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Mon, 18 Dec 2017 15:25:42 +0530
-Subject: [PATCH] config: backup when current config is different from recent
- backup copy
-
-With this change,
-when '/etc/target/saveconfig.json' is same as '/etc/target/backup/saveconfig-${latest-stamp}.json
-we skip backing up saveconfig.json
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- targetcli/ui_root.py | 53 ++++++++++++++++++++++++++++------------------------
- 1 file changed, 29 insertions(+), 24 deletions(-)
-
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index 33bb948..f398395 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -23,6 +23,7 @@ import os
- import re
- import shutil
- import stat
-+import filecmp
- 
- from configshell_fb import ExecutionError
- from rtslib_fb import RTSRoot
-@@ -85,32 +86,36 @@ class UIRoot(UINode):
-                 except OSError as exe:
-                     raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror))
- 
-+            # Only save backups if savefile exits
-             if os.path.exists(savefile):
--                try:
--                    shutil.copy(savefile, backupfile)
--                except IOError as ioe:
--                    backup_error = ioe.strerror or "Unknown error"
--
--                if backup_error == None:
--                    # Kill excess backups
-+                backed_files_list = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
-+                # Save backup if 1. backup dir is empty, or 2. savefile is differnt from recent backup copy
-+                if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile):
-                     try:
--                        with open(universal_prefs_file) as prefs:
--                            backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)]
--                            kept_backups = int(backups[0].split('=')[1].strip())
--                    except:
--                        kept_backups = default_kept_backups
--
--                    backups = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
--                    files_to_unlink = list(reversed(backups))[kept_backups:]
--                    for f in files_to_unlink:
--                        with ignored(IOError):
--                            os.unlink(f)
--
--                    self.shell.log.info("Last %d configs saved in %s." % \
--                                        (kept_backups, backup_dir))
--                else:
--                    self.shell.log.warning("Could not create backup file %s: %s." % \
--                                           (backupfile, backup_error))
-+                        shutil.copy(savefile, backupfile)
-+
-+                    except IOError as ioe:
-+                        backup_error = ioe.strerror or "Unknown error"
-+
-+                    if backup_error == None:
-+                        # Kill excess backups
-+                        try:
-+                            with open(universal_prefs_file) as prefs:
-+                                backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)]
-+                                kept_backups = int(backups[0].split('=')[1].strip())
-+                        except:
-+                            kept_backups = default_kept_backups
-+
-+                        files_to_unlink = list(reversed(backed_files_list))[kept_backups:]
-+                        for f in files_to_unlink:
-+                            with ignored(IOError):
-+                                os.unlink(f)
-+
-+                        self.shell.log.info("Last %d configs saved in %s." % \
-+                                            (kept_backups, backup_dir))
-+                    else:
-+                        self.shell.log.warning("Could not create backup file %s: %s." % \
-+                                               (backupfile, backup_error))
- 
-         self.rtsroot.save_to_file(savefile)
- 
--- 
-1.8.3.1
-
diff --git a/SOURCES/0005-config-rename-key-kept_backups-as-max_backup_files.patch b/SOURCES/0005-config-rename-key-kept_backups-as-max_backup_files.patch
deleted file mode 100644
index 732b1c0..0000000
--- a/SOURCES/0005-config-rename-key-kept_backups-as-max_backup_files.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From bd3b2b50d741848a748830d9a1a7ee642e8d40d3 Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Tue, 19 Dec 2017 14:32:41 +0530
-Subject: [PATCH] config: rename key 'kept_backups' as 'max_backup_files'
-
-$ cat /etc/target/targetcli.conf
-max_backup_files = 25
-
-$ targetcli / saveconfig
-Last 25 configs saved in /etc/target/backup.
-Configuration saved to /etc/target/saveconfig.json
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- targetcli/ui_root.py | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index f398395..f84d33d 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -101,18 +101,18 @@ class UIRoot(UINode):
-                         # Kill excess backups
-                         try:
-                             with open(universal_prefs_file) as prefs:
--                                backups = [line for line in prefs.read().splitlines() if re.match('^kept_backups\s*=', line)]
--                                kept_backups = int(backups[0].split('=')[1].strip())
-+                                backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)]
-+                                max_backup_files = int(backups[0].split('=')[1].strip())
-                         except:
--                            kept_backups = default_kept_backups
-+                            max_backup_files = default_kept_backups
- 
--                        files_to_unlink = list(reversed(backed_files_list))[kept_backups:]
-+                        files_to_unlink = list(reversed(backed_files_list))[max_backup_files:]
-                         for f in files_to_unlink:
-                             with ignored(IOError):
-                                 os.unlink(f)
- 
-                         self.shell.log.info("Last %d configs saved in %s." % \
--                                            (kept_backups, backup_dir))
-+                                            (max_backup_files, backup_dir))
-                     else:
-                         self.shell.log.warning("Could not create backup file %s: %s." % \
-                                                (backupfile, backup_error))
--- 
-1.8.3.1
-
diff --git a/SOURCES/0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch b/SOURCES/0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch
deleted file mode 100644
index 3493991..0000000
--- a/SOURCES/0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch
+++ /dev/null
@@ -1,78 +0,0 @@
-From bf75323d7d678f01c21d0c9825bd55553727e934 Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Fri, 15 Dec 2017 17:23:25 +0530
-Subject: [PATCH] backup: global option to tune max no. of backup conf files
-
-Eg:
-/> set global max_backup_files=1000
-Parameter max_backup_files is now '1000'.
-
-If 'max_backup_files' is set in /etc/target/targetcli.conf, then max value
-between conf file setting and global option settings is considered.
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- scripts/targetcli    | 1 +
- targetcli/ui_node.py | 3 +++
- targetcli/ui_root.py | 8 +++++---
- 3 files changed, 9 insertions(+), 3 deletions(-)
-
-diff --git a/scripts/targetcli b/scripts/targetcli
-index 5404fcd..371edbe 100755
---- a/scripts/targetcli
-+++ b/scripts/targetcli
-@@ -49,6 +49,7 @@ class TargetCLI(ConfigShell):
-                      'auto_add_mapped_luns': True,
-                      'auto_cd_after_create': False,
-                      'auto_save_on_exit': True,
-+                     'max_backup_files': '10',
-                      'auto_add_default_portal': True,
-                     }
- 
-diff --git a/targetcli/ui_node.py b/targetcli/ui_node.py
-index c91dae2..a6982f1 100644
---- a/targetcli/ui_node.py
-+++ b/targetcli/ui_node.py
-@@ -46,6 +46,9 @@ class UINode(ConfigNode):
-         self.define_config_group_param(
-             'global', 'auto_add_default_portal', 'bool',
-             'If true, adds a portal listening on all IPs to new targets.')
-+        self.define_config_group_param(
-+            'global', 'max_backup_files', 'string',
-+            'Max no. of configurations to be backed up in /etc/target/backup/ directory.')
- 
-     def assert_root(self):
-         '''
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index f84d33d..a54845f 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -35,7 +35,6 @@ from .ui_target import UIFabricModule
- 
- default_save_file = "/etc/target/saveconfig.json"
- universal_prefs_file = "/etc/target/targetcli.conf"
--default_kept_backups = 10
- 
- class UIRoot(UINode):
-     '''
-@@ -99,12 +98,15 @@ class UIRoot(UINode):
- 
-                     if backup_error == None:
-                         # Kill excess backups
-+                        max_backup_files = int(self.shell.prefs['max_backup_files'])
-+
-                         try:
-                             with open(universal_prefs_file) as prefs:
-                                 backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)]
--                                max_backup_files = int(backups[0].split('=')[1].strip())
-+                                if max_backup_files < int(backups[0].split('=')[1].strip()):
-+                                    max_backup_files = int(backups[0].split('=')[1].strip())
-                         except:
--                            max_backup_files = default_kept_backups
-+                            self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file)
- 
-                         files_to_unlink = list(reversed(backed_files_list))[max_backup_files:]
-                         for f in files_to_unlink:
--- 
-1.8.3.1
-
diff --git a/SOURCES/0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch b/SOURCES/0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch
deleted file mode 100644
index aa9a488..0000000
--- a/SOURCES/0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From cac1f18c54c87839b4eaa812cd438dc4593c7975 Mon Sep 17 00:00:00 2001
-From: tangwenji <tang.wenji@zte.com.cn>
-Date: Thu, 15 Mar 2018 14:52:20 +0800
-Subject: [PATCH] Fix default max_backup_files in ui_command_saveconfig
-
-Signed-off-by: tangwenji <tang.wenji@zte.com.cn>
----
- targetcli/ui_root.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index a54845f..54d38e3 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -98,7 +98,7 @@ class UIRoot(UINode):
- 
-                     if backup_error == None:
-                         # Kill excess backups
--                        max_backup_files = int(self.shell.prefs['max_backup_files'])
-+                        max_backup_files = int(self.shell.default_prefs['max_backup_files'])
- 
-                         try:
-                             with open(universal_prefs_file) as prefs:
--- 
-1.8.3.1
-
diff --git a/SOURCES/0008-config-add-saveconfig-command-to-StorageObject-level.patch b/SOURCES/0008-config-add-saveconfig-command-to-StorageObject-level.patch
deleted file mode 100644
index b018d94..0000000
--- a/SOURCES/0008-config-add-saveconfig-command-to-StorageObject-level.patch
+++ /dev/null
@@ -1,196 +0,0 @@
-From 9dc85912f6ff2ba77fa8b136478ae3d2776c2b5e Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Sat, 24 Feb 2018 08:38:35 +0530
-Subject: [PATCH] config: add saveconfig command to StorageObject level
-
-$ targetcli /backstores/user:glfs/block1 help
-[...]
-AVAILABLE COMMANDS
-[...]
-    - saveconfig [savefile]
-    - set [group] [parameter=value...]
-    - status
-    - version
-
-$ targetcli /backstores/user:glfs/block1 saveconfig
-Storage Object 'user:block1' config saved to /etc/target/saveconfig.json
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- targetcli/ui_backstore.py |  22 ++++++++++
- targetcli/ui_root.py      | 110 ++++++++++++++++++++++++++--------------------
- 2 files changed, 85 insertions(+), 47 deletions(-)
-
-diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py
-index 5af448f..efa532f 100644
---- a/targetcli/ui_backstore.py
-+++ b/targetcli/ui_backstore.py
-@@ -36,6 +36,8 @@ from rtslib_fb.utils import get_block_type
- 
- from .ui_node import UINode, UIRTSLibNode
- 
-+default_save_file = "/etc/target/saveconfig.json"
-+
- alua_rw_params = ['alua_access_state', 'alua_access_status',
-                   'alua_write_metadata', 'alua_access_type', 'preferred',
-                   'nonop_delay_msecs', 'trans_delay_msecs',
-@@ -702,6 +704,26 @@ class UIStorageObject(UIRTSLibNode):
-         self.shell.con.display("Backstore plugin %s %s"
-                                % (self.rtsnode.plugin, self.rtsnode.version))
- 
-+    def ui_command_saveconfig(self, savefile=None):
-+        '''
-+        Save configuration of this StorageObject.
-+        '''
-+        so = self.rtsnode
-+        rn = self.get_root()
-+
-+        if not savefile:
-+            savefile = default_save_file
-+
-+        savefile = os.path.expanduser(savefile)
-+
-+        rn._save_backups(savefile)
-+
-+        rn.rtsroot.save_to_file(savefile,
-+                                '/backstores/' + so.plugin  + '/' + so.name)
-+
-+        self.shell.log.info("Storage Object '%s:%s' config saved to %s."
-+                            % (so.plugin, so.name, savefile))
-+
- 
- class UIPSCSIStorageObject(UIStorageObject):
-     def summary(self):
-diff --git a/targetcli/ui_root.py b/targetcli/ui_root.py
-index 54d38e3..09f3f1b 100644
---- a/targetcli/ui_root.py
-+++ b/targetcli/ui_root.py
-@@ -62,6 +62,65 @@ class UIRoot(UINode):
-             if fm.wwns == None or any(fm.wwns):
-                 UIFabricModule(fm, self)
- 
-+    def _save_backups(self, savefile):
-+        '''
-+        Take backup of config-file if needed.
-+        '''
-+        # Only save backups if saving to default location
-+        if savefile != default_save_file:
-+            return
-+
-+        backup_dir = os.path.dirname(savefile) + "/backup/"
-+        backup_name = "saveconfig-" + \
-+                      datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json"
-+        backupfile = backup_dir + backup_name
-+        backup_error = None
-+
-+        if not os.path.exists(backup_dir):
-+            try:
-+                os.makedirs(backup_dir);
-+            except OSError as exe:
-+                raise ExecutionError("Cannot create backup directory [%s] %s."
-+                                     % (backup_dir, exc.strerror))
-+
-+        # Only save backups if savefile exits
-+        if not os.path.exists(savefile):
-+            return
-+
-+        backed_files_list = sorted(glob(os.path.dirname(savefile) + \
-+                                   "/backup/*.json"))
-+
-+        # Save backup if backup dir is empty, or savefile is differnt from recent backup copy
-+        if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile):
-+            try:
-+                shutil.copy(savefile, backupfile)
-+
-+            except IOError as ioe:
-+                backup_error = ioe.strerror or "Unknown error"
-+
-+            if backup_error == None:
-+                # remove excess backups
-+                max_backup_files = int(self.shell.prefs['max_backup_files'])
-+
-+                try:
-+                    with open(universal_prefs_file) as prefs:
-+                        backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)]
-+                        if max_backup_files < int(backups[0].split('=')[1].strip()):
-+                            max_backup_files = int(backups[0].split('=')[1].strip())
-+                except:
-+                    self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file)
-+
-+                files_to_unlink = list(reversed(backed_files_list))[max_backup_files:]
-+                for f in files_to_unlink:
-+                    with ignored(IOError):
-+                        os.unlink(f)
-+
-+                self.shell.log.info("Last %d configs saved in %s."
-+                                    % (max_backup_files, backup_dir))
-+            else:
-+                self.shell.log.warning("Could not create backup file %s: %s."
-+                                       % (backupfile, backup_error))
-+
-     def ui_command_saveconfig(self, savefile=default_save_file):
-         '''
-         Saves the current configuration to a file so that it can be restored
-@@ -69,55 +128,12 @@ class UIRoot(UINode):
-         '''
-         self.assert_root()
- 
-+        if not savefile:
-+            savefile = default_save_file
-+
-         savefile = os.path.expanduser(savefile)
- 
--        # Only save backups if saving to default location
--        if savefile == default_save_file:
--            backup_dir = os.path.dirname(savefile) + "/backup"
--            backup_name = "saveconfig-" + \
--                datetime.now().strftime("%Y%m%d-%H:%M:%S") + ".json"
--            backupfile = backup_dir + "/" + backup_name
--            backup_error = None
--
--            if not os.path.exists(backup_dir):
--                try:
--                    os.makedirs(backup_dir);
--                except OSError as exe:
--                    raise ExecutionError("Cannot create backup directory [%s] %s." % (backup_dir, exc.strerror))
--
--            # Only save backups if savefile exits
--            if os.path.exists(savefile):
--                backed_files_list = sorted(glob(os.path.dirname(savefile) + "/backup/*.json"))
--                # Save backup if 1. backup dir is empty, or 2. savefile is differnt from recent backup copy
--                if not backed_files_list or not filecmp.cmp(backed_files_list[-1], savefile):
--                    try:
--                        shutil.copy(savefile, backupfile)
--
--                    except IOError as ioe:
--                        backup_error = ioe.strerror or "Unknown error"
--
--                    if backup_error == None:
--                        # Kill excess backups
--                        max_backup_files = int(self.shell.default_prefs['max_backup_files'])
--
--                        try:
--                            with open(universal_prefs_file) as prefs:
--                                backups = [line for line in prefs.read().splitlines() if re.match('^max_backup_files\s*=', line)]
--                                if max_backup_files < int(backups[0].split('=')[1].strip()):
--                                    max_backup_files = int(backups[0].split('=')[1].strip())
--                        except:
--                            self.shell.log.debug("No universal prefs file '%s'." % universal_prefs_file)
--
--                        files_to_unlink = list(reversed(backed_files_list))[max_backup_files:]
--                        for f in files_to_unlink:
--                            with ignored(IOError):
--                                os.unlink(f)
--
--                        self.shell.log.info("Last %d configs saved in %s." % \
--                                            (max_backup_files, backup_dir))
--                    else:
--                        self.shell.log.warning("Could not create backup file %s: %s." % \
--                                               (backupfile, backup_error))
-+        self._save_backups(savefile)
- 
-         self.rtsroot.save_to_file(savefile)
- 
--- 
-1.8.3.1
-
diff --git a/SOURCES/0009-Support-tcmu-hw-max-sectors.patch b/SOURCES/0009-Support-tcmu-hw-max-sectors.patch
deleted file mode 100644
index 4137170..0000000
--- a/SOURCES/0009-Support-tcmu-hw-max-sectors.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From 2f3183bf56295a764e743d0601275c7aa5a815db Mon Sep 17 00:00:00 2001
-From: Mike Christie <mchristi@redhat.com>
-Date: Wed, 29 Mar 2017 15:01:05 -0500
-Subject: [PATCH] Support tcmu hw max sectors
-
-Support hw_max_sectors setting for tcmu added in this patch:
-
-commit 3abaa2bfdb1e6bb33d38a2e82cf3bb82ec0197bf
-Author: Mike Christie <mchristi@redhat.com>
-Date:   Wed Mar 1 23:14:39 2017 -0600
-
-    tcmu: allow hw_max_sectors greater than 128
----
- targetcli/ui_backstore.py | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py
-index 4c577a4..88240bb 100644
---- a/targetcli/ui_backstore.py
-+++ b/targetcli/ui_backstore.py
-@@ -574,7 +574,8 @@ class UIUserBackedBackstore(UIBackstore):
-             print(x.get("ConfigDesc", "No description."))
-             print()
- 
--    def ui_command_create(self, name, size, cfgstring, wwn=None):
-+    def ui_command_create(self, name, size, cfgstring, wwn=None,
-+                          hw_max_sectors=None):
-         '''
-         Creates a User-backed storage object.
- 
-@@ -598,7 +599,8 @@ class UIUserBackedBackstore(UIBackstore):
-         if not ok:
-             raise ExecutionError("cfgstring invalid: %s" % errmsg)
- 
--        so = UserBackedStorageObject(name, size=size, config=config, wwn=wwn)
-+        so = UserBackedStorageObject(name, size=size, config=config, wwn=wwn,
-+                                     hw_max_sectors=hw_max_sectors)
-         ui_so = UIUserBackedStorageObject(so, self)
-         self.shell.log.info("Created user-backed storage object %s size %d."
-                             % (name, size))
--- 
-1.8.3.1
-
diff --git a/SOURCES/0010-create-add-a-way-to-set-control-string.patch b/SOURCES/0010-create-add-a-way-to-set-control-string.patch
deleted file mode 100644
index 55bae36..0000000
--- a/SOURCES/0010-create-add-a-way-to-set-control-string.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py
-index 3838d02..b60eba5 100644
---- a/targetcli/ui_backstore.py
-+++ b/targetcli/ui_backstore.py
-@@ -577,7 +577,7 @@ class UIUserBackedBackstore(UIBackstore):
-             print()
- 
-     def ui_command_create(self, name, size, cfgstring, wwn=None,
--                          hw_max_sectors=None):
-+                          hw_max_sectors=None, control=None):
-         '''
-         Creates a User-backed storage object.
- 
-@@ -602,7 +602,7 @@ class UIUserBackedBackstore(UIBackstore):
-             raise ExecutionError("cfgstring invalid: %s" % errmsg)
- 
-         so = UserBackedStorageObject(name, size=size, config=config, wwn=wwn,
--                                     hw_max_sectors=hw_max_sectors)
-+                                     hw_max_sectors=hw_max_sectors, control=control)
-         ui_so = UIUserBackedStorageObject(so, self)
-         self.shell.log.info("Created user-backed storage object %s size %d."
-                             % (name, size))
-@@ -633,6 +633,7 @@ class UIStorageObject(UIRTSLibNode):
-         'fabric_max_sectors': ('number', 'Maximum number of sectors the fabric can transfer at once.'),
-         'hw_block_size': ('number', 'Hardware block size in bytes.'),
-         'hw_max_sectors': ('number', 'Maximum number of sectors the hardware can transfer at once.'),
-+        'control': ('string', 'Comma separated string of control=value tuples that will be passed to kernel control file.'),
-         'hw_pi_prot_type': ('number', 'If non-zero, DIF protection is enabled on the underlying hardware.'),
-         'hw_queue_depth': ('number', 'Hardware queue depth.'),
-         'is_nonrot': ('number', 'If set to 1, the backstore is a non rotational device.'),
diff --git a/SOURCES/0011-saveconfig-way-for-block-level-save-with-delete-comm.patch b/SOURCES/0011-saveconfig-way-for-block-level-save-with-delete-comm.patch
deleted file mode 100644
index 76817d0..0000000
--- a/SOURCES/0011-saveconfig-way-for-block-level-save-with-delete-comm.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From bca03ea400a691e4218113b6d10adb61ce0cd511 Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Fri, 1 Jun 2018 16:15:22 +0530
-Subject: [PATCH] saveconfig: way for block-level save with delete command
-
-currently, we can use block-level save feature for create command and
-reconfig of different attributes, but there is no way to use block-level
-feature for delete command.
-
-This patch introduces 'save' flag (False on default), which can trigger
-saveconfig internally as part of delete command.
-
-$ targetcli /backstores/user:glfs delete test save=True
-Deleted storage object test.
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- targetcli/ui_backstore.py | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py
-index 0af29f0..02695ba 100644
---- a/targetcli/ui_backstore.py
-+++ b/targetcli/ui_backstore.py
-@@ -284,7 +284,7 @@ class UIBackstore(UINode):
-     def summary(self):
-         return ("Storage Objects: %d" % len(self._children), None)
- 
--    def ui_command_delete(self, name):
-+    def ui_command_delete(self, name, save=None):
-         '''
-         Recursively deletes the storage object having the specified I{name}. If
-         there are LUNs using this storage object, they will be deleted too.
-@@ -301,7 +301,8 @@ class UIBackstore(UINode):
-         except ValueError:
-             raise ExecutionError("No storage object named %s." % name)
- 
--        child.rtsnode.delete()
-+        save = self.ui_eval_param(save, 'bool', False)
-+        child.rtsnode.delete(save=save)
-         self.remove_child(child)
-         self.shell.log.info("Deleted storage object %s." % name)
- 
--- 
-1.8.3.1
-
diff --git a/SOURCES/0012-saveconfig-handle-backups-with-block-level-delete.patch b/SOURCES/0012-saveconfig-handle-backups-with-block-level-delete.patch
deleted file mode 100644
index f45c669..0000000
--- a/SOURCES/0012-saveconfig-handle-backups-with-block-level-delete.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From a7254dfc15830eb64ae8d47639889cb6a23bd7f4 Mon Sep 17 00:00:00 2001
-From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
-Date: Tue, 12 Jun 2018 15:36:42 +0530
-Subject: [PATCH] saveconfig: handle backups with block-level delete
-
-Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
----
- targetcli/ui_backstore.py | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/targetcli/ui_backstore.py b/targetcli/ui_backstore.py
-index 02695ba..7af2568 100644
---- a/targetcli/ui_backstore.py
-+++ b/targetcli/ui_backstore.py
-@@ -302,6 +302,10 @@ class UIBackstore(UINode):
-             raise ExecutionError("No storage object named %s." % name)
- 
-         save = self.ui_eval_param(save, 'bool', False)
-+        if save:
-+            rn = self.get_root()
-+            rn._save_backups(default_save_file)
-+
-         child.rtsnode.delete(save=save)
-         self.remove_child(child)
-         self.shell.log.info("Deleted storage object %s." % name)
--- 
-1.8.3.1
-
diff --git a/SPECS/targetcli.spec b/SPECS/targetcli.spec
index de5c36c..932dcb2 100644
--- a/SPECS/targetcli.spec
+++ b/SPECS/targetcli.spec
@@ -4,22 +4,10 @@ Name:           targetcli
 License:        ASL 2.0
 Group:          System Environment/Libraries
 Summary:        An administration shell for storage targets
-Version:        2.1.fb46
-Release:        7%{?dist}
+Version:        2.1.fb49
+Release:        1%{?dist}
 URL:            https://fedorahosted.org/targetcli-fb/
 Source:         https://fedorahosted.org/released/targetcli-fb/%{oname}-%{version}.tar.gz
-Patch0:         0001-Properly-detect-errors-when-writing-backup-files.-Cl.patch
-Patch1:         0002-Read-number-of-backup-files-to-keep-from-file.patch
-Patch2:         0003-config-defend-on-etc-target-backup-directory.patch
-Patch3:         0004-config-backup-when-current-config-is-different-from-.patch
-Patch4:         0005-config-rename-key-kept_backups-as-max_backup_files.patch
-Patch5:         0006-backup-global-option-to-tune-max-no.-of-backup-conf-.patch
-Patch6:         0007-Fix-default-max_backup_files-in-ui_command_saveconfi.patch
-Patch7:         0008-config-add-saveconfig-command-to-StorageObject-level.patch
-Patch8:         0009-Support-tcmu-hw-max-sectors.patch
-Patch9:         0010-create-add-a-way-to-set-control-string.patch
-Patch10:        0011-saveconfig-way-for-block-level-save-with-delete-comm.patch
-Patch11:        0012-saveconfig-handle-backups-with-block-level-delete.patch
 BuildArch:      noarch
 BuildRequires:  python-devel python-setuptools
 Requires:       python-rtslib >= 2.1.fb41, python-configshell, python-ethtool
@@ -33,18 +21,6 @@ users will also need to install and use fcoe-utils.
 
 %prep
 %setup -q -n %{oname}-%{version}
-%patch0 -p1
-%patch1 -p1
-%patch2 -p1
-%patch3 -p1
-%patch4 -p1
-%patch5 -p1
-%patch6 -p1
-%patch7 -p1
-%patch8 -p1
-%patch9 -p1
-%patch10 -p1
-%patch11 -p1
 
 %build
 %{__python} setup.py build
@@ -65,6 +41,9 @@ install -m 644 targetcli.8.gz %{buildroot}%{_mandir}/man8/
 %{_mandir}/man8/targetcli.8.gz
 
 %changelog
+* Tue Jan 29 2019 Maurizio Lombardi <mlombard@redhat.com> - 2.1.fb49-1
+- Rebase to latest upstream version
+
 * Wed Aug 08 2018 Maurizio Lombardi <mlombard@redhat.com> - 2.1.fb46-7
 - Respin a new release of targetcli to avoid problems with TPS tests.