# HG changeset patch # User Paul Boddie # Date 1630446673 -7200 # Node ID 0d71c011a145ed688cff70d02095190bfb48ccef # Parent fc8b3fb6acce0cfba921fe3d1b2c991fe14d4bfd Introduced a potential mechanism for handling concurrent changes to directories whose contents are being listed. diff -r fc8b3fb6acce -r 0d71c011a145 libfsserver/include/fsserver/ext2_file_operations.h --- a/libfsserver/include/fsserver/ext2_file_operations.h Sun Aug 29 23:51:48 2021 +0200 +++ b/libfsserver/include/fsserver/ext2_file_operations.h Tue Aug 31 23:51:13 2021 +0200 @@ -30,6 +30,19 @@ +/* Directory iteration helper type. */ + +class Ext2FileOperations; + +struct Ext2DirectoryIteration +{ + Ext2FileOperations *ops; + int (*func)(struct ext2_dir_entry *, int, int, char *, void *); + void *priv_data; +}; + + + /* An Ext2 file operations collection. */ class Ext2FileOperations @@ -70,6 +83,12 @@ void *priv_data); long read_inode(ext2_ino_t ino_file, struct ext2_inode *inode); + + /* Callback method. */ + + int directory_iterate_fn(struct ext2_dir_entry *dir_entry, + int offset, int blocksize, + char *buf, struct Ext2DirectoryIteration *priv_data); }; // vim: tabstop=4 expandtab shiftwidth=4 diff -r fc8b3fb6acce -r 0d71c011a145 libfsserver/lib/files/ext2_file_operations.cc --- a/libfsserver/lib/files/ext2_file_operations.cc Sun Aug 29 23:51:48 2021 +0200 +++ b/libfsserver/lib/files/ext2_file_operations.cc Tue Aug 31 23:51:13 2021 +0200 @@ -155,6 +155,54 @@ ext2fs_file_write(file, addr, size, NULL); } +/* Obtain information for the given inode. */ + +long Ext2FileOperations::read_inode(ext2_ino_t ino, struct ext2_inode *inode) +{ + std::lock_guard guard(_lock); + + if (ext2fs_read_inode(_fs, ino, inode)) + return -L4_EIO; + + return L4_EOK; +} + + + +/* Directory iteration support. */ + +/* Callback function invoking the callback method. */ + +static int _directory_iterate_fn(struct ext2_dir_entry *dir_entry, + int offset, int blocksize, char *buf, + void *priv_data) +{ + struct Ext2DirectoryIteration *data = reinterpret_cast(priv_data); + + return data->ops->directory_iterate_fn(dir_entry, offset, blocksize, buf, data); +} + +/* Callback method invoking the actual callback, with control over locking. */ + +int Ext2FileOperations::directory_iterate_fn(struct ext2_dir_entry *dir_entry, + int offset, int blocksize, + char *buf, struct Ext2DirectoryIteration *priv_data) +{ + /* Release the lock to allow other operations to proceed. */ + + _lock.unlock(); + + /* Invoke the actual callback function. */ + + struct Ext2DirectoryIteration *data = reinterpret_cast(priv_data); + int result = data->func(dir_entry, offset, blocksize, buf, data->priv_data); + + /* Acquire the lock and continue iteration. */ + + _lock.lock(); + return result; +} + /* Initiate iteration over a directory, with the given 'func' being called with directory entry details for each entry. */ @@ -163,20 +211,30 @@ char *, void *), void *priv_data) { - if (ext2fs_dir_iterate(_fs, dir, 0, 0, func, priv_data)) - return -L4_EIO; + /* NOTE: Iteration should probably be interrupted if it appears that the + directory has been modified and the structure of the data has + been changed. This condition might then cause iteration to begin + again, skipping ahead to the entry after the last visited entry. */ - return L4_EOK; -} + /* Acquire the lock for iteration to proceed safely. */ + + _lock.lock(); -long Ext2FileOperations::read_inode(ext2_ino_t ino_file, struct ext2_inode *inode) -{ - std::lock_guard guard(_lock); + /* Begin iteration using the given callback function to invoke a callback + method in this object that will wrap the actual callback with locking + operations. */ + + struct Ext2DirectoryIteration data = {this, func, priv_data}; + int result = ext2fs_dir_iterate(_fs, dir, 0, 0, _directory_iterate_fn, &data); - if (ext2fs_read_inode(_fs, ino_file, inode)) + /* Release the lock upon finishing iteration. */ + + _lock.unlock(); + + if (result) return -L4_EIO; - - return L4_EOK; + else + return L4_EOK; } // vim: tabstop=4 expandtab shiftwidth=4