Split overlay filesystem into attribute_overlay and write_overlay.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29255 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2009-02-19 21:11:59 +00:00
parent f3950b1f72
commit af4245f8a3
2 changed files with 187 additions and 1479 deletions
@@ -34,24 +34,12 @@
#endif
namespace overlay {
namespace attribute_overlay {
class AttributeFile;
class AttributeEntry;
struct open_cookie {
int open_mode;
void * super_cookie;
};
struct write_buffer {
write_buffer * next;
off_t position;
size_t length;
uint8 buffer[1];
};
struct attribute_dir_cookie {
AttributeFile * file;
uint32 index;
@@ -63,16 +51,11 @@ public:
OverlayVolume(fs_volume *volume);
~OverlayVolume();
status_t AllLayersMounted();
fs_volume * Volume() { return fVolume; }
fs_volume * SuperVolume() { return fVolume->super_volume; }
bool WriteSupport() { return fWriteSupport; }
private:
fs_volume * fVolume;
bool fWriteSupport;
};
@@ -92,25 +75,11 @@ public:
status_t GetAttributeFile(AttributeFile **attributeFile);
status_t WriteAttributeFile();
status_t ReadStat(struct stat *stat);
status_t Open(int openMode, void **cookie);
status_t Close(void *cookie);
status_t FreeCookie(void *cookie);
status_t Read(void *cookie, off_t position, void *buffer,
size_t *length);
status_t Write(void *cookie, off_t position,
const void *buffer, size_t *length);
private:
OverlayVolume * fVolume;
fs_vnode fSuperVnode;
ino_t fInodeNumber;
AttributeFile * fAttributeFile;
write_buffer * fWriteBuffers;
off_t fOriginalNodeLength;
off_t fCurrentNodeLength;
time_t fModificationTime;
};
@@ -223,8 +192,7 @@ private:
OverlayVolume::OverlayVolume(fs_volume *volume)
: fVolume(volume),
fWriteSupport(false)
: fVolume(volume)
{
}
@@ -234,19 +202,6 @@ OverlayVolume::~OverlayVolume()
}
status_t
OverlayVolume::AllLayersMounted()
{
fs_info info;
fs_volume *superVolume = fVolume->super_volume;
if (superVolume->ops->read_fs_info != NULL
&& superVolume->ops->read_fs_info(superVolume, &info) == B_OK)
fWriteSupport = (info.flags & B_FS_IS_READONLY) != 0;
return B_OK;
}
// #pragma mark OverlayInode
@@ -255,10 +210,7 @@ OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode,
: fVolume(volume),
fSuperVnode(*superVnode),
fInodeNumber(inodeNumber),
fAttributeFile(NULL),
fWriteBuffers(NULL),
fOriginalNodeLength(-1),
fCurrentNodeLength(-1)
fAttributeFile(NULL)
{
TRACE("inode created\n");
}
@@ -268,13 +220,6 @@ OverlayInode::~OverlayInode()
{
TRACE("inode destroyed\n");
delete fAttributeFile;
write_buffer *element = fWriteBuffers;
while (element) {
write_buffer *next = element->next;
free(element);
element = next;
}
}
@@ -329,238 +274,6 @@ OverlayInode::WriteAttributeFile()
}
status_t
OverlayInode::ReadStat(struct stat *stat)
{
if (fSuperVnode.ops->read_stat == NULL)
return B_UNSUPPORTED;
status_t result = fSuperVnode.ops->read_stat(SuperVolume(), &fSuperVnode,
stat);
if (result != B_OK)
return result;
if (fVolume->WriteSupport() && fCurrentNodeLength >= 0) {
stat->st_size = fCurrentNodeLength;
stat->st_blocks = (stat->st_size + stat->st_blksize - 1)
/ stat->st_blksize;
stat->st_mtime = fModificationTime;
}
return B_OK;
}
status_t
OverlayInode::Open(int openMode, void **_cookie)
{
if (fSuperVnode.ops->open == NULL)
return B_UNSUPPORTED;
if (fVolume->WriteSupport()) {
open_cookie *cookie = (open_cookie *)malloc(sizeof(open_cookie));
if (cookie == NULL)
return B_NO_MEMORY;
if (fOriginalNodeLength < 0) {
struct stat stat;
status_t result = fSuperVnode.ops->read_stat(SuperVolume(),
&fSuperVnode, &stat);
if (result != B_OK)
return result;
fOriginalNodeLength = stat.st_size;
fCurrentNodeLength = stat.st_size;
fModificationTime = stat.st_mtime;
}
cookie->open_mode = openMode;
*_cookie = cookie;
if (openMode & O_TRUNC)
fCurrentNodeLength = 0;
openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT);
return fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, openMode,
&cookie->super_cookie);
}
return fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, openMode,
_cookie);
}
status_t
OverlayInode::Close(void *_cookie)
{
if (fVolume->WriteSupport()) {
open_cookie *cookie = (open_cookie *)_cookie;
return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode,
cookie->super_cookie);
}
return fSuperVnode.ops->close(SuperVolume(), &fSuperVnode, _cookie);
}
status_t
OverlayInode::FreeCookie(void *_cookie)
{
if (fVolume->WriteSupport()) {
open_cookie *cookie = (open_cookie *)_cookie;
status_t result = fSuperVnode.ops->free_cookie(SuperVolume(),
&fSuperVnode, cookie->super_cookie);
free(cookie);
return result;
}
return fSuperVnode.ops->free_cookie(SuperVolume(), &fSuperVnode, _cookie);
}
status_t
OverlayInode::Read(void *_cookie, off_t position, void *buffer, size_t *length)
{
if (fVolume->WriteSupport()) {
if (position >= fCurrentNodeLength) {
*length = 0;
return B_OK;
}
if (position < fOriginalNodeLength) {
open_cookie *cookie = (open_cookie *)_cookie;
size_t readLength = MIN(fOriginalNodeLength - position, *length);
status_t result = fSuperVnode.ops->read(SuperVolume(), &fSuperVnode,
cookie->super_cookie, position, buffer, &readLength);
if (result != B_OK)
return result;
}
// overlay the read with whatever chunks we have written
write_buffer *element = fWriteBuffers;
*length = MIN(fCurrentNodeLength - position, *length);
off_t end = position + *length;
while (element) {
if (element->position > end)
break;
off_t elementEnd = element->position + element->length;
if (elementEnd > position) {
off_t copyPosition = MAX(position, element->position);
size_t copyLength = MIN(elementEnd - position, *length);
memcpy((uint8 *)buffer + (copyPosition - position),
element->buffer + (copyPosition - element->position),
copyLength);
}
element = element->next;
}
return B_OK;
}
return fSuperVnode.ops->read(SuperVolume(), &fSuperVnode, _cookie,
position, buffer, length);
}
status_t
OverlayInode::Write(void *_cookie, off_t position, const void *buffer,
size_t *length)
{
if (fVolume->WriteSupport()) {
// find insertion point
write_buffer **link = &fWriteBuffers;
write_buffer *other = fWriteBuffers;
write_buffer *swallow = NULL;
off_t newPosition = position;
size_t newLength = *length;
uint32 swallowCount = 0;
while (other) {
off_t newEnd = newPosition + newLength;
off_t otherEnd = other->position + other->length;
if (otherEnd < newPosition) {
// other is completely before us
link = &other->next;
other = other->next;
continue;
}
if (other->position > newEnd) {
// other is completely past us
break;
}
swallowCount++;
if (swallow == NULL)
swallow = other;
if (other->position <= newPosition) {
if (swallowCount == 1 && otherEnd >= newEnd) {
// other chunk completely covers us, just copy
memcpy(other->buffer + (newPosition - other->position),
buffer, *length);
fModificationTime = time(NULL);
notify_stat_changed(SuperVolume()->id, fInodeNumber,
B_STAT_MODIFICATION_TIME);
return B_OK;
}
newLength += newPosition - other->position;
newPosition = other->position;
}
if (otherEnd > newEnd)
newLength += otherEnd - newEnd;
other = other->next;
}
write_buffer *element = (write_buffer *)malloc(sizeof(write_buffer) - 1
+ newLength);
if (element == NULL)
return B_NO_MEMORY;
element->next = *link;
element->position = newPosition;
element->length = newLength;
*link = element;
bool sizeChanged = false;
off_t newEnd = newPosition + newLength;
if (newEnd > fCurrentNodeLength) {
fCurrentNodeLength = newEnd;
sizeChanged = true;
}
// populate the buffer with the existing chunks
if (swallowCount > 0) {
while (swallowCount-- > 0) {
memcpy(element->buffer + (swallow->position - newPosition),
swallow->buffer, swallow->length);
element->next = swallow->next;
free(swallow);
swallow = element->next;
}
}
memcpy(element->buffer + (position - newPosition), buffer, *length);
fModificationTime = time(NULL);
notify_stat_changed(SuperVolume()->id, fInodeNumber,
B_STAT_MODIFICATION_TIME | (sizeChanged ? B_STAT_SIZE : 0));
return B_OK;
}
return fSuperVnode.ops->write(SuperVolume(), &fSuperVnode, _cookie,
position, buffer, length);
}
// #pragma mark AttributeFile
@@ -1510,7 +1223,8 @@ overlay_access(fs_volume *volume, fs_vnode *vnode, int mode)
static status_t
overlay_read_stat(fs_volume *volume, fs_vnode *vnode, struct stat *stat)
{
return ((OverlayInode *)vnode->private_node)->ReadStat(stat);
OVERLAY_CALL(read_stat, stat)
return B_UNSUPPORTED;
}
@@ -1535,21 +1249,24 @@ overlay_create(fs_volume *volume, fs_vnode *vnode, const char *name,
static status_t
overlay_open(fs_volume *volume, fs_vnode *vnode, int openMode, void **cookie)
{
return ((OverlayInode *)vnode->private_node)->Open(openMode, cookie);
OVERLAY_CALL(open, openMode, cookie)
return B_UNSUPPORTED;
}
static status_t
overlay_close(fs_volume *volume, fs_vnode *vnode, void *cookie)
{
return ((OverlayInode *)vnode->private_node)->Close(cookie);
OVERLAY_CALL(close, cookie)
return B_UNSUPPORTED;
}
static status_t
overlay_free_cookie(fs_volume *volume, fs_vnode *vnode, void *cookie)
{
return ((OverlayInode *)vnode->private_node)->FreeCookie(cookie);
OVERLAY_CALL(free_cookie, cookie)
return B_UNSUPPORTED;
}
@@ -1557,8 +1274,8 @@ static status_t
overlay_read(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
void *buffer, size_t *length)
{
return ((OverlayInode *)vnode->private_node)->Read(cookie, pos, buffer,
length);
OVERLAY_CALL(read, cookie, pos, buffer, length)
return B_UNSUPPORTED;
}
@@ -1566,8 +1283,8 @@ static status_t
overlay_write(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
const void *buffer, size_t *length)
{
return ((OverlayInode *)vnode->private_node)->Write(cookie, pos, buffer,
length);
OVERLAY_CALL(write, cookie, pos, buffer, length)
return B_UNSUPPORTED;
}
@@ -1759,8 +1476,7 @@ overlay_read_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
void *buffer, size_t *length)
{
OVERLAY_CALL(read_attr, cookie, pos, buffer, length)
AttributeEntry *entry = (AttributeEntry *)cookie;
return entry->Read(pos, buffer, length);
return ((AttributeEntry *)cookie)->Read(pos, buffer, length);
}
@@ -1769,8 +1485,7 @@ overlay_write_attr(fs_volume *volume, fs_vnode *vnode, void *cookie, off_t pos,
const void *buffer, size_t *length)
{
OVERLAY_CALL(write_attr, cookie, pos, buffer, length)
AttributeEntry *entry = (AttributeEntry *)cookie;
return entry->Write(pos, buffer, length);
return ((AttributeEntry *)cookie)->Write(pos, buffer, length);
}
@@ -1779,8 +1494,7 @@ overlay_read_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
struct stat *stat)
{
OVERLAY_CALL(read_attr_stat, cookie, stat)
AttributeEntry *entry = (AttributeEntry *)cookie;
return entry->ReadStat(stat);
return ((AttributeEntry *)cookie)->ReadStat(stat);
}
@@ -1789,8 +1503,7 @@ overlay_write_attr_stat(fs_volume *volume, fs_vnode *vnode, void *cookie,
const struct stat *stat, int statMask)
{
OVERLAY_CALL(write_attr_stat, cookie, stat, statMask)
AttributeEntry *entry = (AttributeEntry *)cookie;
return entry->WriteStat(stat, statMask);
return ((AttributeEntry *)cookie)->WriteStat(stat, statMask);
}
@@ -1973,9 +1686,6 @@ overlay_read_fs_info(fs_volume *volume, struct fs_info *info)
if (result != B_OK)
return result;
OverlayVolume *overlayVolume = (OverlayVolume *)volume->private_volume;
if (overlayVolume->WriteSupport())
info->flags &= ~B_FS_IS_READONLY;
info->flags |= B_FS_HAS_MIME | B_FS_HAS_ATTR /*| B_FS_HAS_QUERY*/;
return B_OK;
}
@@ -2147,7 +1857,7 @@ overlay_rewind_query(fs_volume *volume, void *cookie)
static status_t
overlay_all_layers_mounted(fs_volume *volume)
{
return ((OverlayVolume *)volume->private_volume)->AllLayersMounted();
return B_OK;
}
@@ -2241,14 +1951,14 @@ overlay_std_ops(int32 op, ...)
static file_system_module_info sOverlayFileSystem = {
{
"file_systems/overlay"B_CURRENT_FS_API_VERSION,
"file_systems/attribute_overlay"B_CURRENT_FS_API_VERSION,
0,
overlay_std_ops,
},
"overlay", // short_name
"Overlay File System", // pretty_name
0, // DDM flags
"attribute_overlay", // short_name
"Attribute Overlay File System", // pretty_name
0, // DDM flags
// scanning
NULL, // identify_partition
@@ -2281,9 +1991,9 @@ static file_system_module_info sOverlayFileSystem = {
NULL // initialize
};
} // namespace _overlay
} // namespace attribute_overlay
using namespace overlay;
using namespace attribute_overlay;
module_info *modules[] = {
(module_info *)&sOverlayFileSystem,
File diff suppressed because it is too large Load Diff