Re: [RFC][PATCH 00/11] track files for checkpointability

Alexey Dobriyan
2009-03-05T17:34:02Z

On Thu, Mar 05, 2009 at 08:38:57AM -0800, Dave Hansen wrote:
> This takes a suggestion of Ingo's along with comments from lots of
> other people. It can track whether a given file is able to be
> checkpointed. It introduces a f_op to allow easy customization
> like the reset of the VFS.

Here is how alternative looks like
* without touching VFS at all
* without adding default handlers
* without duplicate code every ->checkpoint hook will have
* without largely useless "special file" messages
(what's so special about it?)
* without adding userspace-visible /proc/*/checkpointable
* without recalculating "checkpointable" property on fs_struct
on every C/R=y kernel.

* with "ban by default" policy as well
* with error message immediatly understandable by developer:

cr_check_file: can't checkpoint file f61a0f40, ->f_op = socket_file_ops+0x0/0x1c0

It may lack some printk, but printks are trivial to insert including
using d_path for precise info.

static int cr_check_file(struct file *file)
{
struct inode *inode = file->f_path.dentry->d_inode;
unsigned int major, minor;

if (d_unhashed(file->f_path.dentry))
return -EINVAL;
#ifdef CONFIG_SECURITY
if (file->f_security)
return -EINVAL;
#endif
#ifdef CONFIG_EPOLL
spin_lock(&file->f_ep_lock);
if (!list_empty(&file->f_ep_links)) {
spin_unlock(&file->f_ep_lock);
return -EINVAL;
}
spin_unlock(&file->f_ep_lock);
#endif

switch (inode->i_mode & S_IFMT) {
case S_IFREG:
case S_IFDIR:
/* Likely on-disk filesystem. */
/* FIXME: FUSE, NFS, other networking filesystems */
if (inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)
return 0;
break;
case S_IFBLK:
major = imajor(inode);
minor = iminor(inode);
printk("%s: can't checkpoint block device %u:%u, ->f_op = %pS\n", __func__, major, minor, file->f_op);
return -EINVAL;
case S_IFCHR:
major = imajor(inode);
minor = iminor(inode);
if (major == UNIX98_PTY_SLAVE_MAJOR)
return 0;
printk("%s: can't checkpoint char device %u:%u, ->f_op = %pS\n", __func__, major, minor, file->f_op);
return -EINVAL;
case S_IFIFO:
break;
case S_IFSOCK:
return 0;
case S_IFLNK:
/* One can't open symlink. */
BUG();
}
printk("%s: can't checkpoint file %p, ->f_op = %pS\n", __func__, file, file->f_op);
return -EINVAL;
}

static int __cr_collect_file(struct cr_context *ctx, struct file *file)
{
struct cr_object *obj;

obj = cr_find_obj_by_ptr(ctx, file, CR_CTX_FILE);
if (obj) {
obj->o_count++;
return 0;
}

obj = cr_object_create(file);
if (!obj)
return -ENOMEM;
list_add_tail(&obj->o_list, &ctx->cr_obj[CR_CTX_FILE]);
printk("collect file %p\n", file);
return 0;
}

int cr_collect_file(struct cr_context *ctx, struct file *file)
{
int rv;

rv = cr_check_file(file);
if (rv < 0)
return rv;
return __cr_collect_file(ctx, file);
}