Merge pull request #68 from versity/zab/collection_of_fixes

Zab/collection of fixes
This commit is contained in:
Zach Brown
2022-01-24 11:22:41 -08:00
committed by GitHub
20 changed files with 366 additions and 127 deletions

View File

@@ -511,7 +511,7 @@ out:
else if (ino == 0)
inode = NULL;
else
inode = scoutfs_iget(sb, ino, 0);
inode = scoutfs_iget(sb, ino, 0, 0);
/*
* We can't splice dir aliases into the dcache. dir entries

View File

@@ -81,7 +81,7 @@ static struct dentry *scoutfs_fh_to_dentry(struct super_block *sb,
trace_scoutfs_fh_to_dentry(sb, fh_type, sfid);
if (scoutfs_valid_fileid(fh_type))
inode = scoutfs_iget(sb, le64_to_cpu(sfid->ino), 0);
inode = scoutfs_iget(sb, le64_to_cpu(sfid->ino), 0, SCOUTFS_IGF_LINKED);
return d_obtain_alias(inode);
}
@@ -100,7 +100,7 @@ static struct dentry *scoutfs_fh_to_parent(struct super_block *sb,
if (scoutfs_valid_fileid(fh_type) &&
fh_type == FILEID_SCOUTFS_WITH_PARENT)
inode = scoutfs_iget(sb, le64_to_cpu(sfid->parent_ino), 0);
inode = scoutfs_iget(sb, le64_to_cpu(sfid->parent_ino), 0, SCOUTFS_IGF_LINKED);
return d_obtain_alias(inode);
}
@@ -123,7 +123,7 @@ static struct dentry *scoutfs_get_parent(struct dentry *child)
scoutfs_dir_free_backref_path(sb, &list);
trace_scoutfs_get_parent(sb, inode, ino);
inode = scoutfs_iget(sb, ino, 0);
inode = scoutfs_iget(sb, ino, 0, SCOUTFS_IGF_LINKED);
return d_obtain_alias(inode);
}

View File

@@ -276,7 +276,7 @@ static void load_inode(struct inode *inode, struct scoutfs_inode *cinode)
set_item_info(si, cinode);
}
static void init_inode_key(struct scoutfs_key *key, u64 ino)
void scoutfs_inode_init_key(struct scoutfs_key *key, u64 ino)
{
*key = (struct scoutfs_key) {
.sk_zone = SCOUTFS_FS_ZONE,
@@ -296,8 +296,7 @@ static void init_inode_key(struct scoutfs_key *key, u64 ino)
* fields because they should have already had a locked refreshed inode
* to be dereferencing its contents.
*/
int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock,
int flags)
int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock)
{
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
struct super_block *sb = inode->i_sb;
@@ -317,7 +316,7 @@ int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock,
if (atomic64_read(&si->last_refreshed) == refresh_gen)
return 0;
init_inode_key(&key, scoutfs_ino(inode));
scoutfs_inode_init_key(&key, scoutfs_ino(inode));
mutex_lock(&si->item_mutex);
if (atomic64_read(&si->last_refreshed) < refresh_gen) {
@@ -697,21 +696,20 @@ struct inode *scoutfs_ilookup(struct super_block *sb, u64 ino)
return ilookup5(sb, ino, scoutfs_iget_test, &ino);
}
struct inode *scoutfs_iget(struct super_block *sb, u64 ino, int lkf)
struct inode *scoutfs_iget(struct super_block *sb, u64 ino, int lkf, int igf)
{
struct scoutfs_lock *lock = NULL;
struct scoutfs_inode_info *si;
struct inode *inode;
struct inode *inode = NULL;
int ret;
ret = scoutfs_lock_ino(sb, SCOUTFS_LOCK_READ, lkf, ino, &lock);
if (ret)
return ERR_PTR(ret);
if (ret < 0)
goto out;
inode = iget5_locked(sb, ino, scoutfs_iget_test, scoutfs_iget_set,
&ino);
inode = iget5_locked(sb, ino, scoutfs_iget_test, scoutfs_iget_set, &ino);
if (!inode) {
inode = ERR_PTR(-ENOMEM);
ret = -ENOMEM;
goto out;
}
@@ -721,20 +719,33 @@ struct inode *scoutfs_iget(struct super_block *sb, u64 ino, int lkf)
atomic64_set(&si->last_refreshed, 0);
inode->i_version = 0;
ret = scoutfs_inode_refresh(inode, lock, 0);
if (ret == 0)
ret = scoutfs_omap_inc(sb, ino);
if (ret) {
iget_failed(inode);
inode = ERR_PTR(ret);
} else {
set_inode_ops(inode);
unlock_new_inode(inode);
ret = scoutfs_inode_refresh(inode, lock);
if (ret < 0)
goto out;
if ((igf & SCOUTFS_IGF_LINKED) && inode->i_nlink == 0) {
ret = -ENOENT;
goto out;
}
ret = scoutfs_omap_inc(sb, ino);
if (ret < 0)
goto out;
set_inode_ops(inode);
unlock_new_inode(inode);
}
ret = 0;
out:
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
if (ret < 0) {
if (inode)
iget_failed(inode);
inode = ERR_PTR(ret);
}
return inode;
}
@@ -803,7 +814,7 @@ int scoutfs_dirty_inode_item(struct inode *inode, struct scoutfs_lock *lock)
store_inode(&sinode, inode);
init_inode_key(&key, scoutfs_ino(inode));
scoutfs_inode_init_key(&key, scoutfs_ino(inode));
ret = scoutfs_item_update(sb, &key, &sinode, sizeof(sinode), lock);
if (!ret)
@@ -1022,7 +1033,7 @@ void scoutfs_update_inode_item(struct inode *inode, struct scoutfs_lock *lock,
ret = update_indices(sb, si, ino, inode->i_mode, &sinode, lock_list);
BUG_ON(ret);
init_inode_key(&key, ino);
scoutfs_inode_init_key(&key, ino);
err = scoutfs_item_update(sb, &key, &sinode, sizeof(sinode), lock);
if (err) {
@@ -1421,7 +1432,7 @@ struct inode *scoutfs_new_inode(struct super_block *sb, struct inode *dir,
set_inode_ops(inode);
store_inode(&sinode, inode);
init_inode_key(&key, scoutfs_ino(inode));
scoutfs_inode_init_key(&key, scoutfs_ino(inode));
ret = scoutfs_omap_inc(sb, ino);
if (ret < 0)
@@ -1546,7 +1557,7 @@ static int delete_inode_items(struct super_block *sb, u64 ino, struct scoutfs_lo
goto out;
}
init_inode_key(&key, ino);
scoutfs_inode_init_key(&key, ino);
ret = scoutfs_item_lookup_exact(sb, &key, &sinode, sizeof(sinode),
lock);
@@ -1855,7 +1866,7 @@ static void inode_orphan_scan_worker(struct work_struct *work)
}
/* try to cached and evict unused inode to delete, can be racing */
inode = scoutfs_iget(sb, ino, 0);
inode = scoutfs_iget(sb, ino, 0, 0);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
if (ret == -ENOENT)

View File

@@ -80,9 +80,11 @@ int scoutfs_drop_inode(struct inode *inode);
void scoutfs_evict_inode(struct inode *inode);
void scoutfs_inode_queue_iput(struct inode *inode);
struct inode *scoutfs_iget(struct super_block *sb, u64 ino, int lkf);
#define SCOUTFS_IGF_LINKED (1 << 0) /* enoent if nlink == 0 */
struct inode *scoutfs_iget(struct super_block *sb, u64 ino, int lkf, int igf);
struct inode *scoutfs_ilookup(struct super_block *sb, u64 ino);
void scoutfs_inode_init_key(struct scoutfs_key *key, u64 ino);
void scoutfs_inode_init_index_key(struct scoutfs_key *key, u8 type, u64 major,
u32 minor, u64 ino);
int scoutfs_inode_index_start(struct super_block *sb, u64 *seq);
@@ -117,8 +119,7 @@ u64 scoutfs_inode_data_version(struct inode *inode);
void scoutfs_inode_get_onoff(struct inode *inode, s64 *on, s64 *off);
int scoutfs_complete_truncate(struct inode *inode, struct scoutfs_lock *lock);
int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock,
int flags);
int scoutfs_inode_refresh(struct inode *inode, struct scoutfs_lock *lock);
int scoutfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
int scoutfs_setattr(struct dentry *dentry, struct iattr *attr);

View File

@@ -1320,6 +1320,84 @@ out:
return ret ?: count;
}
static long scoutfs_ioc_get_allocated_inos(struct file *file, unsigned long arg)
{
struct super_block *sb = file_inode(file)->i_sb;
struct scoutfs_ioctl_get_allocated_inos __user *ugai = (void __user *)arg;
struct scoutfs_ioctl_get_allocated_inos gai;
struct scoutfs_lock *lock = NULL;
struct scoutfs_key key;
struct scoutfs_key end;
u64 __user *uinos;
u64 bytes;
u64 ino;
int nr;
int ret;
if (!(file->f_mode & FMODE_READ)) {
ret = -EBADF;
goto out;
}
if (!capable(CAP_SYS_ADMIN)) {
ret = -EPERM;
goto out;
}
if (copy_from_user(&gai, ugai, sizeof(gai))) {
ret = -EFAULT;
goto out;
}
if ((gai.inos_ptr & (sizeof(__u64) - 1)) || (gai.inos_bytes < sizeof(__u64))) {
ret = -EINVAL;
goto out;
}
scoutfs_inode_init_key(&key, gai.start_ino);
scoutfs_inode_init_key(&end, gai.start_ino | SCOUTFS_LOCK_INODE_GROUP_MASK);
uinos = (void __user *)gai.inos_ptr;
bytes = gai.inos_bytes;
nr = 0;
ret = scoutfs_lock_ino(sb, SCOUTFS_LOCK_READ, 0, gai.start_ino, &lock);
if (ret < 0)
goto out;
while (bytes >= sizeof(*uinos)) {
ret = scoutfs_item_next(sb, &key, &end, NULL, 0, lock);
if (ret < 0) {
if (ret == -ENOENT)
ret = 0;
break;
}
if (key.sk_zone != SCOUTFS_FS_ZONE) {
ret = 0;
break;
}
/* all fs items are owned by allocated inodes, and _first is always ino */
ino = le64_to_cpu(key._sk_first);
if (put_user(ino, uinos)) {
ret = -EFAULT;
break;
}
uinos++;
bytes -= sizeof(*uinos);
if (++nr == INT_MAX)
break;
scoutfs_inode_init_key(&key, ino + 1);
}
scoutfs_unlock(sb, lock, SCOUTFS_LOCK_READ);
out:
return ret ?: nr;
}
long scoutfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd) {
@@ -1353,6 +1431,8 @@ long scoutfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return scoutfs_ioc_resize_devices(file, arg);
case SCOUTFS_IOC_READ_XATTR_TOTALS:
return scoutfs_ioc_read_xattr_totals(file, arg);
case SCOUTFS_IOC_GET_ALLOCATED_INOS:
return scoutfs_ioc_get_allocated_inos(file, arg);
}
return -ENOTTY;

View File

@@ -520,4 +520,43 @@ struct scoutfs_ioctl_xattr_total {
#define SCOUTFS_IOC_READ_XATTR_TOTALS \
_IOW(SCOUTFS_IOCTL_MAGIC, 15, struct scoutfs_ioctl_read_xattr_totals)
/*
* This fills the caller's inos array with inode numbers that are in use
* after the start ino, within an internal inode group.
*
* This only makes a promise about the state of the inode numbers within
* the first and last numbers returned by one call. At one time, all of
* those inodes were still allocated. They could have changed before
* the call returned. And any numbers outside of the first and last
* (or single) are undefined.
*
* This doesn't iterate over all allocated inodes, it only probes a
* single group that the start inode is within. This interface was
* first introduced to support tests that needed to find out about a
* specific inode, while having some other similarly niche uses. It is
* unsuitable for a consistent iteration over all the inode numbers in
* use.
*
* This test of inode items doesn't serialize with the inode lifetime
* mechanism. It only tells you the numbers of inodes that were once
* active in the system and haven't yet been fully deleted. The inode
* numbers returned could have been in the process of being deleted and
* were already unreachable even before the call started.
*
* @start_ino: the first inode number that could be returned
* @inos_ptr: pointer to an aligned array of 64bit inode numbers
* @inos_bytes: the number of bytes available in the inos_ptr array
*
* Returns errors or the count of inode numbers returned, quite possibly
* including 0.
*/
struct scoutfs_ioctl_get_allocated_inos {
__u64 start_ino;
__u64 inos_ptr;
__u64 inos_bytes;
};
#define SCOUTFS_IOC_GET_ALLOCATED_INOS \
_IOW(SCOUTFS_IOCTL_MAGIC, 16, struct scoutfs_ioctl_get_allocated_inos)
#endif

View File

@@ -1050,7 +1050,7 @@ int scoutfs_lock_inode(struct super_block *sb, enum scoutfs_lock_mode mode, int
goto out;
if (flags & SCOUTFS_LKF_REFRESH_INODE) {
ret = scoutfs_inode_refresh(inode, *lock, flags);
ret = scoutfs_inode_refresh(inode, *lock);
if (ret < 0) {
scoutfs_unlock(sb, *lock, mode);
*lock = NULL;

View File

@@ -675,28 +675,18 @@ static void scoutfs_net_recv_worker(struct work_struct *work)
scoutfs_tseq_add(&ninf->msg_tseq_tree, &mrecv->tseq_entry);
/*
* We want to drain the proc_workq in order to ensure that
* that the inflight lock recovery work is fully flushed out
* so that we can prevent the client/server racing trying to
* do lock recovery and processing farewell at the same time.
*/
if (nh.cmd == SCOUTFS_NET_CMD_FAREWELL && conn->listening_conn)
drain_workqueue(conn->proc_workq);
/*
* Initial received greetings and farewell are processed
* Initial received greetings are processed
* synchronously before any other incoming messages.
*
* Incoming requests or responses to the lock client are
* called synchronously to avoid reordering.
*/
if (nh.cmd == SCOUTFS_NET_CMD_GREETING ||
(nh.cmd == SCOUTFS_NET_CMD_FAREWELL && conn->listening_conn) ||
(nh.cmd == SCOUTFS_NET_CMD_LOCK && !conn->listening_conn))
scoutfs_net_proc_worker(&mrecv->proc_work);
else
queue_work(conn->proc_workq, &mrecv->proc_work);
queue_work(conn->workq, &mrecv->proc_work);
}
if (ret)
@@ -861,7 +851,6 @@ static void scoutfs_net_destroy_worker(struct work_struct *work)
}
destroy_workqueue(conn->workq);
destroy_workqueue(conn->proc_workq);
scoutfs_tseq_del(&ninf->conn_tseq_tree, &conn->tseq_entry);
kfree(conn->info);
trace_scoutfs_conn_destroy_free(conn);
@@ -1161,8 +1150,6 @@ static void scoutfs_net_shutdown_worker(struct work_struct *work)
/* wait for socket and proc work to finish, includes chained work */
drain_workqueue(conn->workq);
drain_workqueue(conn->proc_workq);
/* tear down the sock now that all work is done */
if (conn->sock) {
sock_release(conn->sock);
@@ -1360,7 +1347,7 @@ scoutfs_net_alloc_conn(struct super_block *sb,
return NULL;
}
conn->workq = alloc_workqueue("scoutfs_net_workq_%s",
conn->workq = alloc_workqueue("scoutfs_net_%s",
WQ_UNBOUND | WQ_NON_REENTRANT, 0,
name_suffix);
if (!conn->workq) {
@@ -1369,16 +1356,6 @@ scoutfs_net_alloc_conn(struct super_block *sb,
return NULL;
}
conn->proc_workq = alloc_workqueue("scoutfs_net_proc_workq_%s",
WQ_UNBOUND | WQ_NON_REENTRANT, 0,
name_suffix);
if (!conn->proc_workq) {
destroy_workqueue(conn->workq);
kfree(conn->info);
kfree(conn);
return NULL;
}
conn->sb = sb;
conn->notify_up = notify_up;
conn->notify_down = notify_down;
@@ -1411,14 +1388,6 @@ scoutfs_net_alloc_conn(struct super_block *sb,
return conn;
}
/* Give the caller the client info of the connection. This is used by
* server processing the server_farewell, and lock response/recovery.
*/
void *scoutfs_net_client_info(struct scoutfs_net_connection *conn)
{
return conn->info;
}
/*
* Give the caller the client rid of the connection. This used by rare
* server processing callers who want to send async responses after
@@ -1803,23 +1772,6 @@ int scoutfs_net_response_node(struct super_block *sb,
NULL, NULL, NULL);
}
/*
* The response function that was submitted with the request is not
* called if the request is canceled here.
*/
void scoutfs_net_cancel_request(struct super_block *sb,
struct scoutfs_net_connection *conn,
u8 cmd, u64 id)
{
struct message_send *msend;
spin_lock(&conn->lock);
msend = find_request(conn, cmd, id);
if (msend)
complete_send(conn, msend);
spin_unlock(&conn->lock);
}
struct sync_request_completion {
struct completion comp;
void *resp;

View File

@@ -63,7 +63,6 @@ struct scoutfs_net_connection {
atomic64_t recv_seq;
struct workqueue_struct *workq;
struct workqueue_struct *proc_workq;
struct work_struct listen_work;
struct work_struct connect_work;
struct work_struct send_work;
@@ -116,7 +115,6 @@ scoutfs_net_alloc_conn(struct super_block *sb,
scoutfs_net_notify_t notify_up,
scoutfs_net_notify_t notify_down, size_t info_size,
scoutfs_net_request_t *req_funcs, char *name_suffix);
void *scoutfs_net_client_info(struct scoutfs_net_connection *conn);
u64 scoutfs_net_client_rid(struct scoutfs_net_connection *conn);
int scoutfs_net_connect(struct super_block *sb,
struct scoutfs_net_connection *conn,
@@ -136,9 +134,6 @@ int scoutfs_net_submit_request_node(struct super_block *sb,
u64 rid, u8 cmd, void *arg, u16 arg_len,
scoutfs_net_response_t resp_func,
void *resp_data, u64 *id_ret);
void scoutfs_net_cancel_request(struct super_block *sb,
struct scoutfs_net_connection *conn,
u8 cmd, u64 id);
int scoutfs_net_sync_request(struct super_block *sb,
struct scoutfs_net_connection *conn,
u8 cmd, void *arg, unsigned arg_len,

View File

@@ -262,7 +262,7 @@ void scoutfs_recov_shutdown(struct super_block *sb)
recinf->timeout_fn = NULL;
spin_unlock(&recinf->lock);
list_for_each_entry_safe(pend, tmp, &recinf->pending, head) {
list_for_each_entry_safe(pend, tmp, &list, head) {
list_del(&pend->head);
kfree(pend);
}

View File

@@ -122,7 +122,6 @@ struct server_info {
struct server_client_info {
u64 rid;
struct list_head head;
bool received_farewell;
};
static __le64 *first_valopt(struct scoutfs_volume_options *valopt)
@@ -172,7 +171,7 @@ static bool test_shutting_down(struct server_info *server)
static void set_shutting_down(struct server_info *server, bool val)
{
server->shutting_down = val;
smp_rmb();
smp_wmb();
}
static void stop_server(struct server_info *server)
@@ -1506,15 +1505,11 @@ static int server_lock(struct super_block *sb,
struct scoutfs_net_connection *conn,
u8 cmd, u64 id, void *arg, u16 arg_len)
{
struct server_client_info *sci = scoutfs_net_client_info(conn);
u64 rid = scoutfs_net_client_rid(conn);
if (arg_len != sizeof(struct scoutfs_net_lock))
return -EINVAL;
if (sci->received_farewell)
return scoutfs_net_response(sb, conn, cmd, id, -EINVAL, NULL, 0);
return scoutfs_lock_server_request(sb, rid, id, arg);
}
@@ -1523,15 +1518,11 @@ static int lock_response(struct super_block *sb,
void *resp, unsigned int resp_len,
int error, void *data)
{
struct server_client_info *sci = scoutfs_net_client_info(conn);
u64 rid = scoutfs_net_client_rid(conn);
if (resp_len != sizeof(struct scoutfs_net_lock))
return -EINVAL;
if (sci->received_farewell)
return 0;
return scoutfs_lock_server_response(sb, rid, resp);
}
@@ -1569,15 +1560,11 @@ static int lock_recover_response(struct super_block *sb,
void *resp, unsigned int resp_len,
int error, void *data)
{
struct server_client_info *sci = scoutfs_net_client_info(conn);
u64 rid = scoutfs_net_client_rid(conn);
if (invalid_recover(resp, resp_len))
return -EINVAL;
if (sci->received_farewell)
return 0;
return scoutfs_lock_server_recover_response(sb, rid, resp);
}
@@ -3462,6 +3449,18 @@ static void farewell_worker(struct work_struct *work)
}
}
/*
* Responses that are ready to send can be further delayed by
* moving them back to the reqs list.
*/
list_for_each_entry_safe(fw, tmp, &send, entry) {
/* finish lock recovery before destroying locks, fenced if too long */
if (scoutfs_recov_is_pending(sb, fw->rid, SCOUTFS_RECOV_LOCKS)) {
list_move_tail(&fw->entry, &reqs);
quo_reqs++;
}
}
/* clean up resources for mounts before sending responses */
list_for_each_entry_safe(fw, tmp, &send, entry) {
ret = reclaim_rid(sb, fw->rid);
@@ -3529,11 +3528,9 @@ static int server_farewell(struct super_block *sb,
struct scoutfs_net_connection *conn,
u8 cmd, u64 id, void *arg, u16 arg_len)
{
struct server_client_info *sci = scoutfs_net_client_info(conn);
struct server_info *server = SCOUTFS_SB(sb)->server_info;
u64 rid = scoutfs_net_client_rid(conn);
struct farewell_request *fw;
int ret;
if (arg_len != 0)
return -EINVAL;
@@ -3551,20 +3548,6 @@ static int server_farewell(struct super_block *sb,
list_add_tail(&fw->entry, &server->farewell_requests);
spin_unlock(&server->farewell_lock);
/*
* Tear down client lock server state and set that we recieved farewell
* to ensure that we do not race between client and server trying to process
* lock recovery at the same time (race). We also want to mark that the recovery
* finished so that if client's try to send stuff later; the server doesnt care.
*/
sci->received_farewell = true;
ret = scoutfs_lock_server_farewell(sb, rid);
if (ret < 0) {
kfree(fw);
return ret;
}
scoutfs_server_recov_finish(sb, rid, SCOUTFS_RECOV_LOCKS);
queue_farewell_work(server);
/* response will be sent later */
@@ -3656,8 +3639,14 @@ static void finished_recovery(struct super_block *sb)
void scoutfs_server_recov_finish(struct super_block *sb, u64 rid, int which)
{
DECLARE_SERVER_INFO(sb, server);
if (scoutfs_recov_finish(sb, rid, which) > 0)
finished_recovery(sb);
/* rid's farewell response might be sent after it finishes lock recov */
if (which & SCOUTFS_RECOV_LOCKS)
queue_farewell_work(server);
}
/*

View File

@@ -601,7 +601,7 @@ static int scoutfs_fill_super(struct super_block *sb, void *data, int silent)
goto out;
/* this interruptible iget lets hung mount be aborted with ctl-c */
inode = scoutfs_iget(sb, SCOUTFS_ROOT_INO, SCOUTFS_LKF_INTERRUPTIBLE);
inode = scoutfs_iget(sb, SCOUTFS_ROOT_INO, SCOUTFS_LKF_INTERRUPTIBLE, 0);
if (IS_ERR(inode)) {
ret = PTR_ERR(inode);
if (ret == -ERESTARTSYS)

View File

@@ -227,8 +227,9 @@ test "$T_QUORUM" -le "$T_NR_MOUNTS" || \
die "-q quorum mmembers must not be greater than -n mounts"
# top level paths
T_KMOD=$(realpath "$(dirname $0)/../kmod")
T_UTILS=$(realpath "$T_KMOD/../utils")
T_TESTS=$(realpath "$(dirname $0)")
T_KMOD=$(realpath "$T_TESTS/../kmod")
T_UTILS=$(realpath "$T_TESTS/../utils")
test -d "$T_KMOD" || die "kmod/ repo dir $T_KMOD not directory"
test -d "$T_UTILS" || die "utils/ repo dir $T_UTILS not directory"
@@ -382,7 +383,7 @@ cmd grep . /sys/kernel/debug/tracing/options/trace_printk \
conf="$T_RESULTS/scoutfs-fencd.conf"
cat > $conf << EOF
SCOUTFS_FENCED_DELAY=1
SCOUTFS_FENCED_RUN=$T_UTILS/fenced/local-force-unmount
SCOUTFS_FENCED_RUN=$T_TESTS/fenced-local-force-unmount.sh
SCOUTFS_FENCED_RUN_ARGS=""
EOF
export SCOUTFS_FENCED_CONFIG_FILE="$conf"

View File

@@ -26,7 +26,8 @@ inode_exists()
{
local ino="$1"
handle_cat "$T_M0" "$ino" > "$T_TMP.handle_cat.log" 2>&1
scoutfs get-allocated-inos -i "$ino" -s -p "$T_M0" > $T_TMP.inos.log 2>&1
test "$?" == 0 -a "$(head -1 $T_TMP.inos.log)" == "$ino"
}
echo "== test our inode existance function"

View File

@@ -1,3 +1,6 @@
# delay, in seconds, between each check for pending fence requests.
SCOUTFS_FENCED_DELAY=1
SCOUTFS_FENCED_RUN=/usr/libexec/scoutfs-fenced/run/local-force-unmount
# path to executable to run to service fence request
#SCOUTFS_FENCED_RUN=
# arguments to pass to binary
SCOUTFS_FENCED_RUN_ARGS=""

View File

@@ -617,6 +617,33 @@ command is used first.
.RE
.PD
.TP
.BI "get-allocated-inos [-i|--ino INO] [-s|--single] [-p|--path PATH]"
.sp
This debugging command prints allocated inode numbers. It only prints
inodes
found in the group that contains the starting inode. The printed inode
numbers aren't necessarily reachable. They could be anywhere in the
process from being unlinked to finally deleted when their items
were found.
.RS 1.0i
.PD 0
.TP
.sp
.B "-i, --ino INO"
The first 64bit inode number which could be printed.
.TP
.B "-s, --single"
Only print the single starting inode when it is allocated, all other allocated
inode numbers will be ignored.
.TP
.B "-p, --path PATH"
A path within a ScoutFS filesystem.
.RE
.PD
.TP
.SH SEE ALSO
.BR scoutfs (5),
.BR xattr (7),

View File

@@ -55,7 +55,6 @@ install -m 755 -D src/scoutfs $RPM_BUILD_ROOT%{_sbindir}/scoutfs
install -m 644 -D src/ioctl.h $RPM_BUILD_ROOT%{_includedir}/scoutfs/ioctl.h
install -m 644 -D src/format.h $RPM_BUILD_ROOT%{_includedir}/scoutfs/format.h
install -m 755 -D fenced/scoutfs-fenced $RPM_BUILD_ROOT%{_libexecdir}/scoutfs-fenced/scoutfs-fenced
install -m 755 -D fenced/local-force-unmount $RPM_BUILD_ROOT%{_libexecdir}/scoutfs-fenced/run/local-force-unmount
install -m 644 -D fenced/scoutfs-fenced.service $RPM_BUILD_ROOT%{_unitdir}/scoutfs-fenced.service
install -m 644 -D fenced/scoutfs-fenced.conf.example $RPM_BUILD_ROOT%{_sysconfdir}/scoutfs/scoutfs-fenced.conf.example

View File

@@ -0,0 +1,137 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <argp.h>
#include "sparse.h"
#include "parse.h"
#include "util.h"
#include "format.h"
#include "ioctl.h"
#include "cmd.h"
struct get_allocated_inos_args {
char *path;
u64 ino;
bool have_ino;
bool single;
};
static int do_get_allocated_inos(struct get_allocated_inos_args *args)
{
struct scoutfs_ioctl_get_allocated_inos gai;
u64 *inos = NULL;
int fd = -1;
u64 bytes;
int ret;
int i;
if (args->single)
bytes = sizeof(*inos);
else
bytes = SCOUTFS_LOCK_INODE_GROUP_NR * sizeof(*inos);
inos = malloc(bytes);
if (!inos) {
fprintf(stderr, "inode number array allocation failed\n");
ret = -ENOMEM;
goto out;
}
fd = get_path(args->path, O_RDONLY);
if (fd < 0)
return fd;
memset(&gai, 0, sizeof(gai));
gai.start_ino = args->ino;
gai.inos_ptr = (unsigned long)inos;
gai.inos_bytes = bytes;
ret = ioctl(fd, SCOUTFS_IOC_GET_ALLOCATED_INOS, &gai);
if (ret < 0) {
ret = -errno;
fprintf(stderr, "get_allocated_inos ioctl failed: "
"%s (%d)\n", strerror(errno), errno);
goto out;
}
if (args->single && ret > 0 && inos[0] != args->ino)
ret = 0;
for (i = 0; i < ret; i++)
printf("%llu\n", inos[i]);
ret = 0;
out:
if (fd >= 0)
close(fd);
free(inos);
return ret;
};
static int parse_opt(int key, char *arg, struct argp_state *state)
{
struct get_allocated_inos_args *args = state->input;
int ret;
switch (key) {
case 'i':
ret = parse_u64(arg, &args->ino);
if (ret)
return ret;
args->have_ino = true;
case 'p':
args->path = strdup_or_error(state, arg);
break;
case 's':
args->single = true;
break;
case ARGP_KEY_FINI:
if (!args->have_ino)
argp_error(state, "must provide --ino starting inode number option");
default:
break;
}
return 0;
}
static struct argp_option options[] = {
{ "ino", 'i', "NUMBER", 0, "Start from 64bit inode number (required)"},
{ "path", 'p', "PATH", 0, "Path to ScoutFS filesystem"},
{ "single", 's', NULL, 0, "Only print single specific inode number argument"},
{ NULL }
};
static struct argp argp = {
options,
parse_opt,
NULL,
"Print allocated inode numbers from starting inode number"
};
static int get_allocated_inos_cmd(int argc, char **argv)
{
struct get_allocated_inos_args get_allocated_inos_args = {NULL};
int ret;
ret = argp_parse(&argp, argc, argv, 0, NULL, &get_allocated_inos_args);
if (ret)
return ret;
return do_get_allocated_inos(&get_allocated_inos_args);
}
static void __attribute__((constructor)) get_allocated_inos_ctor(void)
{
cmd_register_argp("get-allocated-inos", &argp, GROUP_DEBUG, get_allocated_inos_cmd);
}

View File

@@ -278,6 +278,8 @@ static int print_log_trees_item(struct scoutfs_key *key, u64 seq, u8 flags, void
" data_freed: "ALCROOT_F"\n"
" srch_file: "SRF_FMT"\n"
" inode_count_delta: %lld\n"
" get_trans_seq: %lld\n"
" commit_trans_seq: %lld\n"
" max_item_seq: %llu\n"
" finalize_seq: %llu\n"
" rid: %016llx\n"
@@ -296,6 +298,8 @@ static int print_log_trees_item(struct scoutfs_key *key, u64 seq, u8 flags, void
ALCROOT_A(&lt->data_freed),
SRF_A(&lt->srch_file),
le64_to_cpu(lt->inode_count_delta),
le64_to_cpu(lt->get_trans_seq),
le64_to_cpu(lt->commit_trans_seq),
le64_to_cpu(lt->max_item_seq),
le64_to_cpu(lt->finalize_seq),
le64_to_cpu(lt->rid),