Commit Graph
798969 Commits
Author SHA1 Message Date
Ernesto A. Fernández 972ebf7b68 apfs: keep the private-dir inode in the superblock
When mounting the filesystem, put a pointer to the private-dir inode in
the superblock.  Use it to simplify the handling of orphan records.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-15 00:10:12 -03:00
Ernesto A. Fernández c4feadd779 apfs: use dir_emit_dots() in apfs_readdir()
Replace the calls to dir_emit_dot() and dir_emit_dotdot() with a single
call to dir_emit_dots().

These functions simply emit the vfs inode number of the current and
parent directories, so they might produce a wrong value on 32-bit
architectures.  I don't believe this can be fixed from inside the
module, because one of our directories could be '..' to another file
system.  BTRFS simply ignores the issue; do the same for now, but add a
comment on it.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-14 00:16:39 -03:00
Ernesto A. Fernández 4025695b53 apfs: silence kernel warning on ->unlink() cleanup
When apfs_unlink() fails, cleanup may involve calling inc_nlink() to
reset the link count from 0 to 1, which triggers a kernel warning.  To
avoid this, temporarily set the inode state to I_LINKABLE.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-13 16:29:31 -03:00
Ernesto A. Fernández a824befa14 apfs: don't reset nlink on apfs_mknod() cleanup
If a fault is injected to apfs_transaction_commit(), creating a file
will deadlock.  The reason is that discard_new_inode() will call iput(),
which involves ->evict_inode() and will try to start a new transaction
that deletes all records for the supposed orphan.  This makes no sense;
avoid resetting the inode link count, and let apfs_transaction_abort()
handle the on-disk cleanup.

It should be noted that all other filesystems I checked do clear nlink
before discard_new_inode(), so there might be an important reason for
this that I'm not seeing.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-13 01:04:56 -03:00
Ernesto A. Fernández a593d24577 apfs: set filesystem read-only on commit failure
Callers don't properly reset in-memory structures after a transaction
commit fails.  For example, apfs_mknod() neglects to reduce the child
count of the parent directory.  This could be fixed of course, but it
seems wasteful: transaction commits can't hit ENOSPC and are unlikely
to hit ENOMEM, so they will typically not fail.

BTRFS always sets the filesystem read-only after aborting a transaction.
We can't follow that example in general because we don't yet preallocate
space, but there is no reason not to do it in this situation.  Adjust
apfs_transaction_start() and apfs_transaction_abort() to deal with these
unexpected read-only filesystems.

Another benefit of this change is that we no longer need to assume that
the checkpoint superblock has synced correctly; check for errors and
fail the commit as usual.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-12 01:41:49 -03:00
Ernesto A. Fernández 652bc7e61e apfs: clean up mess for 64-bit inode numbers
Having separate code to deal with inode numbers in 32-bit architectures
has proved unwise; there is no verified performance benefit from this
and now, after several commits with no testing, the 32-bit code won't
even build.  Fix this with a new const qualifier in the argument to
APFS_I(), and from now on just use the 32-bit version of everything.

It's important to always read the inode number with apfs_ino(), to avoid
getting confused and working with the potentially overflowing i_ino;
remove a few remaining instances of this bug.  Also start setting the
number by means of apfs_set_inode(), but don't touch the hacky code for
private-dir; I intend to turn it into a real inode in the future.

Finally, deal with the TODO regarding insert_inode_locked(): define
apfs_insert_inode_locked() as a wrapper to insert_inode_locked4(),
implementing the same functionality as insert_inode_locked() but with
full support for 32-bit architectures.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-10 00:55:16 -03:00
Ernesto A. Fernández 930ac1900e apfs: implement ->evict_inode() method
Implement the ->evict_inode() superblock operation, which must deal with
orphaned inode records and also their fake hardlinks under private-dir.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-07 23:12:56 -03:00
Ernesto A. Fernández 296f6db803 apfs: use a wrapper for the name of an orphan link
Move the code that names the fake link of an orphan inode from
apfs_create_orphan_link() to a new helper, apfs_orphan_name().  The
intention is to reuse the code when evicting the inode.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-07 17:36:21 -03:00
Ernesto A. Fernández 3e1546a459 apfs: implement ->unlink() directory operation
Implement the ->unlink() directory operation.  It mainly just deletes
the dentry and sibling records, but two complications exist.

Inode records in APFS hold information about the primary link, so when
this link is deleted the inode needs to be modified as well.  Extend
apfs_update_inode() to support this use case.  Since the length of the
name is not fixed, the modified inode record may not fit in the same
location; for now just remove it and insert it again in all cases.  This
requires small tweaks to apfs_btree_remove() and apfs_btree_insert(), so
that queries can pass through them and still point to the right spot.

The other issue is that inodes with no links are not being deleted here,
which leaves them orphaned.  ->evict_inode() is not implemented yet, but
even if it was there could still be a crash before the file is closed.
The official reference says nothing on this matter, but we are allowed
to put anything we want in private-dir, so relink the orphaned inodes in
there for now.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-06 18:42:25 -03:00
Ernesto A. Fernández cbccce3a84 apfs: rework argument to apfs_build_inode_val()
To deal with primary link deletion, apfs_inode_update() will soon need
to use apfs_build_inode_val() without a vfs dentry, so replace that
argument with the filename.  Reorder these two functions as well.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-05 00:23:00 -03:00
Ernesto A. Fernández 208b01774c apfs: add parent_id field to in-memory inode
Each on-disk inode reports the id of its primary parent.  For now the
field is never modified, but that will change when ->unlink() is
implemented.  To make this easy for apfs_update_inode() to handle,
always keep the parent id in memory in the apfs_inode_info structure.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-05 00:22:59 -03:00
Ernesto A. Fernández 63ff292434 apfs: rework arguments of dentry creation functions
Replace the vfs dentry with its name and parent id as parameters
to apfs_create_dentry_rec().  Also adjust its helpers
apfs_build_dentry_key() and apfs_build_dentry_val().

Being able to call this function without a vfs dentry will soon be
useful to deal with orphan inodes.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-05 00:22:58 -03:00
Ernesto A. Fernández 753f87eaad apfs: read sibling ids in apfs_drec_from_query()
Add a new sibling_id field to the apfs_drec_val structure, and make
apfs_drec_from_query() read the sibling id from the xfield when it
exists.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-09-05 00:22:51 -03:00
Ernesto A. Fernández 97d0730642 apfs: don't give sibling records to a single link
A file with a single link does not require a sibling id, or sibling
records; the module makes them to avoid having to modify the records for
the primary link when a second one is added.  This is wasteful, and it's
also insufficient to deal with primary links created by other versions
of APFS.

So start doing this correctly.  To modify the dentry record, just delete
it using a first draft of apfs_btree_remove(), and then make it anew.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-27 20:46:09 -03:00
Ernesto A. Fernández f6fcfcc0ef apfs: move dentry lookups to new function
Define apfs_dentry_lookup() to take care of dentry lookups, using the
code from apfs_inode_by_name().  The intention here was to imitate
apfs_inode_lookup(), but the issue of hash collisions makes it tricky
to avoid parsing the record.

This new function will soon be reused to modify existing directory
records.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-23 23:39:37 -03:00
Ernesto A. Fernández c5d30eebd9 apfs: declare apfs_drec_from_query() as static
Since apfs_drec_from_query() is no longer used outside of dir.c, remove
its declaration from the header and make it static.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-23 21:27:57 -03:00
Ernesto A. Fernández 1b43cec969 apfs: don't update parent in create_dentry_rec()
Don't update the parent's child count in apfs_create_dentry_rec(),
because soon we'll be reusing this function to add a sibling id to an
existing primary link.  Instead define apfs_create_dentry() to handle
the whole process.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-23 20:16:31 -03:00
Ernesto A. Fernández 6aacfcf0da apfs: set owner and mode in apfs_update_inode()
Make apfs_update_inode() copy the owner, group and mode fields of the
on-disk inode record, so that those changes will be committed to disk
when ->write_inode() is called.  For now ignore the inode size, since
writing to a file is not supported.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-22 23:12:13 -03:00
Ernesto A. Fernández d5931e33b3 apfs: implement ->write_inode() method
Use apfs_update_inode() to implement the ->write_inode() superblock
operation.  Don't add support for all the inode fields yet, we'll deal
with that soon.

Note that ext4 seems to believe that this method might be called with an
open handle on a transaction.  That would cause a deadlock, but ignore
it for now.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-22 13:11:26 -03:00
Ernesto A. Fernández c2fd392da0 apfs: use wrappers to handle on-disk timestamps
Define two inline functions to simplify the conversion of on-disk
timestamps to timespec64 structures, and vice versa.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-21 17:45:43 -03:00
Ernesto A. Fernández 13d45e3497 apfs: move inode record updates to new function
Define apfs_update_inode() to take care of updating the on-disk record
for a modified in-memory inode.  For now focus only on the fields needed
by apfs_link() and apfs_create_dentry_rec(); simplify their code with
this new function.

In apfs_link(), also replace the calls to inode_inc_link_count() and
inode_dec_link_count() with inc_nlink() and dec_nlink(), respectively.
This should have been the case from the beginning: there is no need to
dirty the inode if the metadata is written to disk right away.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-20 22:52:48 -03:00
Ernesto A. Fernández b77af9dda6 apfs: keep directory child count in inode info
Add a field for the child count to the apfs_inode_info structure, which
will be set to zero if the inode is not a directory.  The next patch
will need this field to simplify writing inode records.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-20 18:12:06 -03:00
Ernesto A. Fernández 27426274fb apfs: read the inode nlink for special files
This implementation is already capable of creating hard links to special
files, so don't skip reading their link count from disk.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-19 19:51:25 -03:00
Ernesto A. Fernández 5a92ae7a34 apfs: use a wrapper to set catalog key headers
Write an apfs_key_set_hdr() inline function that sets the header of a
raw catalog key from its type and id.  This is needed whenever a new
catalog record is created, so use it to clean up all that code.

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-19 17:56:33 -03:00
Ernesto A. Fernández f668a05305 apfs: reuse apfs_inode_lookup() for writes
Now that apfs_inode_lookup() just finds the inode (as opposed to reading
the whole thing), reuse it to simplify the code for apfs_link() and
apfs_create_dentry_rec().

Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
2019-08-19 16:02:57 -03:00