Skip to content

Commit

Permalink
Modify pool_usage function and callers
Browse files Browse the repository at this point in the history
Fixes the other part of rockstor#1454.

New behaviour is to return only the used space value, but this now also
includes space reserved by btrfs and unavailable for data.
  • Loading branch information
sfranzen committed Oct 5, 2016
1 parent ef2995d commit 6693616
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 60 deletions.
57 changes: 16 additions & 41 deletions src/rockstor/fs/btrfs.py
Expand Up @@ -736,49 +736,24 @@ def shares_usage(pool, share_map, snap_map):


def pool_usage(mnt_pt):
# @todo: remove temporary raid5/6 custom logic once fi usage
# supports raid5/6.
"""Return used space of the storage pool mounted at mnt_pt.
Used space is considered to be:
- All space currently used by data;
- All space currently allocated for metadata and system data.
"""
cmd = [BTRFS, 'fi', 'usage', '-b', mnt_pt]
total = 0
inuse = 0
free = 0
data_ratio = 1
raid56 = False
parity = 1
disks = set()
out, err, rc = run_command(cmd)
for e in err:
e = e.strip()
if (re.match('WARNING: RAID56', e) is not None):
raid56 = True

for o in out:
o = o.strip()
if (raid56 is True and re.match('/dev/', o) is not None):
disks.add(o.split()[0])
elif (raid56 is True and re.match('Data,RAID', o) is not None):
if (o[5:10] == 'RAID6'):
parity = 2
elif (re.match('Device size:', o) is not None):
total = int(o.split()[2]) / 1024
elif (re.match('Used:', o) is not None):
inuse = int(o.split()[1]) / 1024
elif (re.match('Free ', o) is not None):
free = int(o.split()[2]) / 1024
elif (re.match('Data ratio:', o) is not None):
data_ratio = float(o.split()[2])
if (data_ratio < 0.01):
data_ratio = 0.01
if (raid56 is True):
num_disks = len(disks)
if (num_disks > 0):
per_disk = total / num_disks
total = (num_disks - parity) * per_disk
else:
total = total / data_ratio
inuse = inuse / data_ratio
free = total - inuse
return (total, inuse, free)

used = 0
for line in out:
fields = re.split('\W+', line)
if line.startswith('Data'):
used += int(fields[5])
elif re.search('Size', line):
used += int(fields[3])

return used / 1024


def scrub_start(pool, force=False):
Expand Down
18 changes: 7 additions & 11 deletions src/rockstor/storageadmin/models/pool.py
Expand Up @@ -41,21 +41,17 @@ class Pool(models.Model):

@property
def free(self, *args, **kwargs):
#why do we compute pool usage on the fly like this and not like
#share usage as part of state refresh? This is a lot simpler and
#less code. For share usage, this type of logic could slow things
#down quite a bit because there can be 100's of Shares, but number
#of Pools even on a large instance is usually no more than a few.
try:
return pool_usage('%s%s' % (settings.MNT_PT, self.name))[2]
except:
return self.size
# Why do we compute pool usage on the fly like this and not like
# share usage as part of state refresh? This is a lot simpler and
# less code. For share usage, this type of logic could slow things
# down quite a bit because there can be 100's of Shares, but number
# of Pools even on a large instance is usually no more than a few.
return self.size - pool_usage('%s%s' % (settings.MNT_PT, self.name))

@property
def reclaimable(self, *args, **kwargs):
return 0

@property
def usage_bound(self, disk_sizes=[], num_devices=0):
"""Return the total amount of storage possible within this pool's set
of disks, in bytes.
Expand All @@ -64,7 +60,7 @@ def usage_bound(self, disk_sizes=[], num_devices=0):
http://carfax.org.uk/btrfs-usage/js/btrfs-usage.js
"""
if not disk_sizes:
disk_sizes = [int(size) * 1024 for size in self.disk_set
disk_sizes = [int(size) for size in self.disk_set
.values_list('size', flat=True)
.order_by('-size')]
num_devices = len(disk_sizes)
Expand Down
2 changes: 1 addition & 1 deletion src/rockstor/storageadmin/views/command.py
Expand Up @@ -67,7 +67,7 @@ def _refresh_pool_state():
pool_info = get_pool_info(fd.name)
p.name = pool_info['label']
p.raid = pool_raid('%s%s' % (settings.MNT_PT, p.name))['data']
p.size = pool_usage('%s%s' % (settings.MNT_PT, p.name))[0]
p.size = p.usage_bound()
p.save()
except Exception, e:
logger.error('Exception while refreshing state for '
Expand Down
4 changes: 2 additions & 2 deletions src/rockstor/storageadmin/views/disk.py
Expand Up @@ -213,7 +213,7 @@ def _update_disk_state():
# update disk db object to reflect special root pool status
dob.pool = p
dob.save()
p.size = pool_usage(mount_root(p))[0]
p.size = p.usage_bound()
enable_quota(p)
p.uuid = btrfs_uuid(dob.name)
p.save()
Expand Down Expand Up @@ -379,7 +379,7 @@ def _btrfs_disk_import(self, dname, request):
do.save()
mount_root(po)
po.raid = pool_raid('%s%s' % (settings.MNT_PT, po.name))['data']
po.size = pool_usage('%s%s' % (settings.MNT_PT, po.name))[0]
po.size = p.usage_bound()
po.save()
enable_quota(po)
import_shares(po, request)
Expand Down
9 changes: 4 additions & 5 deletions src/rockstor/storageadmin/views/pool.py
Expand Up @@ -273,7 +273,7 @@ def post(self, request):
d.pool = p
d.save()
add_pool(p, dnames)
p.size = pool_usage(mount_root(p))[0]
p.size = p.usage_bound()
p.uuid = btrfs_uuid(dnames[0])
p.save()
return Response(PoolInfoSerializer(p).data)
Expand Down Expand Up @@ -416,11 +416,11 @@ def put(self, request, pname, command):
size_cut = 0
for d in disks:
size_cut += d.size
if (size_cut >= usage[2]):
if (size_cut >= usage):
e_msg = ('Removing these(%s) disks may shrink the pool by '
'%dKB, which is greater than available free space'
' %dKB. This is not supported.' %
(dnames, size_cut, usage[2]))
(dnames, size_cut, usage))
handle_exception(Exception(e_msg), request)

resize_pool(pool, dnames, add=False)
Expand All @@ -435,8 +435,7 @@ def put(self, request, pname, command):
else:
e_msg = ('command(%s) is not supported.' % command)
handle_exception(Exception(e_msg), request)
usage = pool_usage('/%s/%s' % (settings.MNT_PT, pool.name))
pool.size = usage[0]
pool.size = pool.usage_bound()
pool.save()
return Response(PoolInfoSerializer(pool).data)

Expand Down

0 comments on commit 6693616

Please sign in to comment.