Hello,
Mikhail Karpov, le mer. 05 août 2026 23:25:15 +0700, a ecrit:
> On Fri, 31 Jul 2026 02:13:26 Samuel Thibault wrote:
> > Uh? So if the disk image has not partition table at all, libparted says
> > that it has one partition? That's ugly :/ We'd really need to find a
> > way to ask libparted whether there is a partition table or not. Perhaps
> > through comparing the PedDiskType name field against "loop"?
>
> While studying the libparted code, I discovered that dev->type is always set
> to PED_DEVICE_UNKNOWN in libparted/arch/gnu.c:
No, I didn't mean PedDeviceType, but really PedDiskType, in the PedDisk
structure:
PedDisk *disk = ped_disk_new (device);
Then disk->type->name tells you the name of the partition type, which
can be "msdos", "gpt", and probably "loop" when there is no actual
partition table (last detector as last dummy resort).
> dev->type = PED_DEVICE_UNKNOWN; /* It's deprecated anyway */
>
> So first we need to understand how to determine the type based on the
> information the store can provide.
As mentioned, it's probably not worth bothering with implementing the
device type.
> > I don't see the relation with store_parsed?
>
> I mean, we could check store_parsed for 'part:' and, if it detects it, avoid
> calling create_partitions, since we're guaranteed to be working with a
> partition, not the entire disk.
Ok but if the disk itself has no partition table, we have to properly
expose it.
And actually, some partition types can be nested.
> > I was rather thinking about all the code about permission checking and
> > locking that you have in your netfs_S_io_read/write before calling
> > dev_read/write.
>
> We can pass peropen to pager_create instead of dev, and then check
> permissions and locking po->np->lock before calling dev_read/write.
? I don't understand, what is the point of this?
Really, I'm really *only* talking about this code:
netfs_S_io_read (struct protid *cred, data_t *data,
mach_msg_type_number_t *datalen, off_t offset,
vm_size_t amount)
{
debug ("netfs_S_io_read:\n");
if (!cred)
{
debug ("!cred\n");
debug ("netfs_S_io_read return: EOPNOTSUPP\n");
return EOPNOTSUPP;
}
if (!(cred->po->openstat & O_READ))
{
debug ("!(cred->po->openstat & O_READ)\n");
debug ("netfs_S_io_read return: EBADF");
return EBADF;
}
struct node *node = cred->po->np;
pthread_mutex_lock (&node->lock);
size_t data_size = *datalen;
error_t err;
if (offset < 0)
{
err = dev_read (node->nn->dev, cred->po->filepointer, amount,
(void **) data, &data_size);
if (!err)
cred->po->filepointer += data_size;
}
else
err = dev_read (node->nn->dev, offset, amount, (void **) data, &data_size);
pthread_mutex_unlock (&node->lock);
*datalen = data_size;
debug ("netfs_S_io_read return: %d\n", err);
return err;
}
Everything but the call to dev_read are *exact* duplicates of libnetfs'
provided netfs_S_io_read:
kern_return_t
netfs_S_io_read (struct protid *user,
data_t *data,
mach_msg_type_number_t *datalen,
off_t offset,
vm_size_t amount)
{
error_t err;
off_t start;
struct node *node;
int alloced = 0;
size_t data_size = *datalen;
if (!user)
return EOPNOTSUPP;
node = user->po->np;
pthread_mutex_lock (&user->po->np->lock);
if ((user->po->openstat & O_READ) == 0)
{
pthread_mutex_unlock (&node->lock);
return EBADF;
}
if (amount > data_size)
{
void *new_data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
if (new_data == MAP_FAILED)
{
pthread_mutex_unlock (&node->lock);
return errno;
}
alloced = 1;
*data = new_data;
}
data_size = amount;
start = (offset == -1 ? user->po->filepointer : offset);
if (start < 0)
err = EINVAL;
else if (S_ISLNK (node->nn_stat.st_mode))
/* Read from a symlink. */
{
off_t size = node->nn_stat.st_size;
if (start + amount > size)
amount = size - start;
if (amount > size)
amount = size;
if (start >= size)
{
data_size = 0;
err = 0;
}
else if (amount < size || start > 0)
{
char *whole_link = alloca (size);
err = netfs_attempt_readlink (user->user, node, whole_link);
if (! err)
{
memcpy (*data, whole_link + start, amount);
data_size = amount;
}
}
else
{
err = netfs_attempt_readlink (user->user, node, *data);
data_size = amount;
}
}
else
/* Read from a normal file. */
err = netfs_attempt_read (user->user, node, start, &data_size, *data);
if (offset == -1 && !err)
user->po->filepointer += data_size;
pthread_mutex_unlock (&node->lock);
if (err && alloced)
munmap (*data, amount);
if (!err && alloced && (round_page (data_size) < round_page (amount)))
munmap (*data + round_page (data_size),
round_page (amount) - round_page (data_size));
*datalen = data_size;
return err;
}
The only spurious part is the S_ISLNK case, but we don't need to care.
*All* I'm saying is that instead of defining netfs_S_io_read, you can
probably simply define netfs_attempt_read, something like:
error_t
netfs_attempt_read (struct iouser * cred, struct node * node,
off_t offset, size_t * len, void *data)
{
return dev_read(node->nn->dev, offset, *len, &data, len);
}
Way less duplicated code to maintain.
And similarly for netfs_S_io_write.
And netfs_S_io_map can probably be implemented by just providing
netfs_get_filemap.
And netfs_S_io_readable can probably be implemented by making
netfs_validate_stat actually fill np->nn_stat so libnetfs'
implementation of netfs_S_io_readable will just work already.
Samuel