[PATCH 07/23] Move inode number and generation into ino_gen struct

Zach Brown zab at zabbo.net
Wed Apr 9 12:28:47 PDT 2025


On Fri, Apr 04, 2025 at 08:45:23PM +0200, Valerie Aurora wrote:
> Files/dirs are uniquely identifed by the combination of inode number
> and generation number. The generation number is incremented every time
> an inode is freed and reallocated. In almost every case, we should use
> both inode and generation number when performing operations. Encourage
> this by using a combination inode number/generation struct. Also
> remove the unused inode number argument from init_dirent_args().

> @@ -268,7 +269,7 @@ static int debugfs_func(int argc, char **argv)
>  	struct ngnfs_fs_info nfi = INIT_NGNFS_FS_INFO;
>  	struct debugfs_context ctx = {
>  		.nfi = &nfi,
> -		.cwd_ino = NGNFS_ROOT_INO,
> +		.cwd_ig = { NGNFS_ROOT_INO, 1 },

Wouldn't this use the INIT_NGNFS_ROOT_IG initializer?

> @@ -52,9 +52,9 @@ static u64 name_hash(void *name, size_t name_len)
>   * copy in and out any dirent as we work with them.
>   */
>  struct dirent_args {
> +	struct ngnfs_inode_ino_gen ig;
>  	u64 hash;
>  	size_t dent_size;
> -	u64 ino;

Do we need this, given that the dent has an ig?  It'd be nice if we
didn't need both.   Maybe that native ino was a bit lazy.. 

> -static int update_dirent_args_ino(struct dirent_args *da, u64 ino)
> +/* caller has filled out da->ig, update the dent.ig to match */
> +static int update_dirent_args_dent(struct dirent_args *da)
>  {
> -	da->dent.ino = cpu_to_le64(ino);
> +	da->dent.ig.ino = cpu_to_le64(da->ig.ino);
> +	da->dent.ig.gen = cpu_to_le64(da->ig.gen);

This went from taking the ino argument, to operating on the ig already
stored in the dirent.  That doesn't seem quite right.. we don't want to
hide all in/out relationships in these arg structs and end up with
functionally global variables that the code paths are operating on.

> +int ngnfs_dir_create(struct ngnfs_fs_info *nfi, struct ngnfs_inode_ino_gen *dir, umode_t mode,
> +		     char *name, size_t name_len)
>  {
>  	struct {
>  		struct ngnfs_transaction txn;
>  		struct ngnfs_inode_txn_ref dir;
>  		struct ngnfs_inode_txn_ref inode;
> -		u64 ino;

If we had an ig here..

> +		      ngnfs_inode_alloc(nfi, &op->txn, &op->da.ig, &op->inode)			?:

Then it could be allocated into here..

> +		      update_dirent_args_dent(&op->da)						?:

And set in the da->dent here, and we wouldn't need the duplicating of
the ig in both da-> and da->dent. .  Maybe?  Hopefully?

> +/*
> + * The inode generation number changes every time a specific inode is
> + * freed and reallocated. The inode number and generation number
> + * uniquely identify a file/dir over its lifetime. This lets users of
> + * references to inodes find out if the inode has changed out from
> + * underneath them. Generally, the inode number and generation number
> + * should be referenced together, so make a struct to keep them
> + * together.
> + */
> +
> +struct ngnfs_ino_gen {
> +	__le64 ino;	/* inode number, starts at 1 */
> +	__le64 gen;	/* inode generation, starts at 1 */
> +};

Loving all the commentary here, thanks for taking the time.

> +int ngnfs_inode_alloc(struct ngnfs_fs_info *nfi, struct ngnfs_transaction *txn,
> +		      struct ngnfs_inode_ino_gen *ig, struct ngnfs_inode_txn_ref *itref)
>  {
> -	u64 bnr;
> +	struct ngnfs_inode_ino_gen new;
>  	int ret;
>  
> -	ret = ngnfs_txn_alloc_meta(txn, &bnr) ?:
> -	      ngnfs_inode_get(nfi, txn, NBF_WRITE | NBF_NEW, bnr, itref);
> +	new.gen = 1; /* XXX should look up previous gen and increment */

Agreed.  FWIW, this'll be in block metadata that's stored by devd, even
for freed blocks, and sent/received over the wire along with block
contents.

- z



More information about the ngnfs-devel mailing list