Re: [RFC][PATCH 5/8] add f_op for checkpointability

From: Dave Hansen
Date: Fri Feb 27 2009 - 21:51:56 EST


On Fri, 2009-02-27 at 18:14 -0800, Sukadev Bhattiprolu wrote:
> | -int cr_file_supported(struct file *file)
> | +typedef int (do_checkpoint_t)(struct file *, struct cr_ctx *,
> | + struct cr_hdr_fd *);
> | +
> | +int generic_file_checkpoint(struct file *file, struct cr_ctx *ctx,
> | + struct cr_hdr_fd *hh)
> | +{
> | + /*
> | + * A NULL hh means to make a trial run not
> | + * actually writing data. Just determine
> | + * if the file is checkpointable.
> | + */
> | + if (!hh)
> | + return 0;
> | +
> | + hh->f_flags = file->f_flags;
> | + hh->f_mode = file->f_mode;
> | + hh->f_pos = file->f_pos;
> | + hh->f_version = file->f_version;
> | + /* FIX: need also file->uid, file->gid, file->f_owner, etc */
> | +
> | + return 0;
> | +}
> | +
> | +do_checkpoint_t *cr_file_get_func(struct file *file)
> | {
>
> Do we really need this helper ? IOW do callers need this function pointer
> itself ? Or can we have a more generic helper that callers can use both
> check if checkpoint is possible (pass NULL in ctx and hh) and to actually
> checkpoint. Something like:

That helper is there because I overload that f_op->checkpoint for both
the "is this file checkpointable" function and the "checkpoint this
file" operation.

> int cr_file_checkpoint(file, ctx, hh)
> {
> int rc = -1;
>
> if (!cr_fs_checkpointable(fstype))
> return rc;
>
> if (!cr_file_checkpointable(file))
> return rc;
>
> if (special_file(file))
> return rc;
>
> op = file->f_op->checkpoint;
> if (!op)
> op = generic_file_checkpoint;
>
> return (*op)(file, ctx, hh);
> }

First thing you have to be careful about is that the f_op should be able
to override *everything*. So it has to be first, always.

The other part is that I'd prefer not to call check (a la !
cr_file_checkpointable()) then try to checkpoint a second later, since
we share the implementation between the two here.

You are probably right that we should probably be able to do this:

int cr_file_checkpointable(file)
{
return !cr_file_checkpoint(file, NULL, NULL);
}

I'll look into that and see how natural it is to implement.

> | struct inode *inode = file->f_dentry->d_inode;
> | struct file_system_type *fs_type = inode->i_sb->s_type;
> |
> | - if (fs_is_cr_able(fs_type))
> | - return 0;
> | + if (file->f_op->checkpoint)
> | + return file->f_op->checkpoint;
> | +
> | + if (!fs_is_cr_able(fs_type))
> | + return NULL;
> |
> | if (special_file(inode->i_mode))
> | - return 0;
> | + return NULL;
> |
> | - return 1;
> | + return generic_file_checkpoint;
> | +}
> | +
> | +int cr_file_supported(struct file *file)
> | +{
> | + do_checkpoint_t *func = cr_file_get_func(file);
> | +
> | + if (func)
> | + return !func(file, NULL, NULL);
> | +
> | + return 0;
> | }
> |
> | /* cr_write_fd_data - dump the state of a given file pointer */
> | static int cr_write_fd_data(struct cr_ctx *ctx, struct file *file, int parent)
> | {
> | + do_checkpoint_t *ckpt_func;
> | struct cr_hdr h;
> | struct cr_hdr_fd *hh = cr_hbuf_get(ctx, sizeof(*hh));
> | - struct dentry *dent = file->f_dentry;
> | - struct inode *inode = dent->d_inode;
> | - enum fd_type fd_type;
> | int ret;
> |
> | h.type = CR_HDR_FD_DATA;
> | h.len = sizeof(*hh);
> | h.parent = parent;
> |
> | - hh->f_flags = file->f_flags;
> | - hh->f_mode = file->f_mode;
> | - hh->f_pos = file->f_pos;
> | - hh->f_version = file->f_version;
> | - /* FIX: need also file->uid, file->gid, file->f_owner, etc */
> | -
> | - switch (inode->i_mode & S_IFMT) {
> | - case S_IFREG:
> | - fd_type = CR_FD_FILE;
> | - break;
> | - case S_IFDIR:
> | - fd_type = CR_FD_DIR;
> | - break;
> | - default:
> | - cr_hbuf_put(ctx, sizeof(*hh));
> | - return -EBADF;
> | - }
> | + ckpt_func = cr_file_get_func(file);
> | + ret = -EBADF;
> | + if (!ckpt_func)
> | + goto out;
> |
> | - /* FIX: check if the file/dir/link is unlinked */
> | - hh->fd_type = fd_type;
> | + ret = ckpt_func(file, ctx, hh);
> | + if (ret)
> | + goto out;
>
> So we can combine these two steps into just one ?
>
> ret = -EBADF;
> hh->fd_type = fd_type;
> if (cr_file_checkpoint(file, ctx, hh))
> goto out;

We could but it would be harder to read. :)

I really don't like operational things inside if()s like that. I think
it kinda hides important code.

Thanks for taking the time to look at this, Suka.

-- Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/