mirror of
https://github.com/versity/scoutfs.git
synced 2026-04-27 00:25:06 +00:00
Returning ENOSPC is challenging because we have clients working on allocators which are a fraction of the whole and we use COW transactions so we need to be able to allocate to free. This adds support for returning ENOSPC to client posix allocators as free space gets low. For metadata, we reserve a number of free blocks for making progress with client and server transactions which can free space. The server sets the low flag in a client's allocator if we start to dip into reserved blocks. In the client we add an argument to entering a transaction which indicates if we're allocating new space (as opposed to just modifying existing data or freeing). When an allocating transaction runs low and the server low flag is set then we return ENOSPC. Adding an argument to transaciton holders and having it return ENOSPC gave us the opportunity to clean it up and make it a little clearer. More work is done outside the wait_event function and it now specifically waits for a transaction to cycle when it forces a commit rather than spinning until the transaction worker acquires the lock and stops it. For data the same pattern applies except there are no reserved blocks and we don't COW data so it's a simple case of returning the hard ENOSPC when the data allocator flag is set. The server needs to consider the reserved count when refilling the client's meta_avail allocator and when swapping between the two meta_avail and meta_free allocators. We add the reserved metadata block count to statfs_more so that df can subtract it from the free meta blocks and make it clear when enospc is going to be returned for metadata allocations. We increase the minimum device size in mkfs so that small testing devices provide sufficient reserved blocks. And finally we add a little test that makes sure we can fill both metadata and data to ENOSPC and then recover by deleting what we filled. Signed-off-by: Zach Brown <zab@versity.com>
22 lines
750 B
C
22 lines
750 B
C
#ifndef _SCOUTFS_TRANS_H_
|
|
#define _SCOUTFS_TRANS_H_
|
|
|
|
void scoutfs_trans_write_func(struct work_struct *work);
|
|
int scoutfs_trans_sync(struct super_block *sb, int wait);
|
|
int scoutfs_file_fsync(struct file *file, loff_t start, loff_t end,
|
|
int datasync);
|
|
void scoutfs_trans_restart_sync_deadline(struct super_block *sb);
|
|
|
|
int scoutfs_hold_trans(struct super_block *sb, bool allocing);
|
|
bool scoutfs_trans_held(void);
|
|
void scoutfs_release_trans(struct super_block *sb);
|
|
u64 scoutfs_trans_sample_seq(struct super_block *sb);
|
|
|
|
int scoutfs_trans_get_log_trees(struct super_block *sb);
|
|
bool scoutfs_trans_has_dirty(struct super_block *sb);
|
|
|
|
int scoutfs_setup_trans(struct super_block *sb);
|
|
void scoutfs_shutdown_trans(struct super_block *sb);
|
|
|
|
#endif
|