int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
+ char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
locking rules:
none have BKL
d_delete: yes no yes no
d_release: no no no yes
d_iput: no no no yes
+d_dname: no no no no
--------------------------- inode_operations ---------------------------
prototypes:
operations. Dentries and the dcache are the domain of the VFS and the
individual filesystem implementations. Device drivers have no business
here. These methods may be set to NULL, as they are either optional or
-the VFS uses a default. As of kernel 2.6.13, the following members are
+the VFS uses a default. As of kernel 2.6.22, the following members are
defined:
struct dentry_operations {
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
+ char *(*d_dname)(struct dentry *, char *, int);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
VFS calls iput(). If you define this method, you must call
iput() yourself
+ d_dname: called when the pathname of a dentry should be generated.
+ Usefull for some pseudo filesystems (sockfs, pipefs, ...) to delay
+ pathname generation. (Instead of doing it when dentry is created,
+ its done only when the path is needed.). Real filesystems probably
+ dont want to use it, because their dentries are present in global
+ dcache hash, so their hash should be an invariant. As no lock is
+ held, d_dname() should not try to modify the dentry itself, unless
+ appropriate SMP safety is used. CAUTION : d_path() logic is quite
+ tricky. The correct way to return for example "Hello" is to put it
+ at the end of the buffer, and returns a pointer to the first char.
+ dynamic_dname() helper function is provided to take care of this.
+
+Example :
+
+static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
+{
+ return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+ dentry->d_inode->i_ino);
+}
+
Each dentry has a pointer to its parent dentry, as well as a hash list
of child dentries. Child dentries are basically like files in a
directory.
struct vfsmount *rootmnt;
struct dentry *root;
+ /*
+ * We have various synthetic filesystems that never get mounted. On
+ * these filesystems dentries are never used for lookup purposes, and
+ * thus don't need to be hashed. They also don't need a name until a
+ * user wants to identify the object in /proc/pid/fd/. The little hack
+ * below allows us to generate a name for these objects on demand:
+ */
+ if (dentry->d_op && dentry->d_op->d_dname)
+ return dentry->d_op->d_dname(dentry, buf, buflen);
+
read_lock(¤t->fs->lock);
rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
return res;
}
+/*
+ * Helper function for dentry_operations.d_dname() members
+ */
+char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
+ const char *fmt, ...)
+{
+ va_list args;
+ char temp[64];
+ int sz;
+
+ va_start(args, fmt);
+ sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
+ va_end(args);
+
+ if (sz > sizeof(temp) || sz > buflen)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ buffer += buflen - sz;
+ return memcpy(buffer, temp, sz);
+}
+
/*
* NOTE! The user-level library version returns a
* character pointer. The kernel system call just
return 0;
}
+/*
+ * pipefs_dname() is called from d_path().
+ */
+static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+ return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+ dentry->d_inode->i_ino);
+}
+
static struct dentry_operations pipefs_dentry_operations = {
.d_delete = pipefs_delete_dentry,
+ .d_dname = pipefs_dname,
};
static struct inode * get_pipe_inode(void)
struct inode *inode;
struct file *f;
struct dentry *dentry;
- char name[32];
- struct qstr this;
+ struct qstr name = { .name = "" };
f = get_empty_filp();
if (!f)
if (!inode)
goto err_file;
- this.len = sprintf(name, "[%lu]", inode->i_ino);
- this.name = name;
- this.hash = 0;
err = -ENOMEM;
- dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
+ dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
if (!dentry)
goto err_inode;
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
+ char *(*d_dname)(struct dentry *, char *, int);
};
/* the dentry parameter passed to d_hash and d_compare is the parent
/* validate "insecure" dentry pointer */
extern int d_validate(struct dentry *, struct dentry *);
+/*
+ * helper function for dentry_operations.d_dname() members
+ */
+extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
+
extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
/* Allocation counts.. */
dentry->d_flags |= DCACHE_UNHASHED;
return 0;
}
+
+/*
+ * sockfs_dname() is called from d_path().
+ */
+static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+ return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
+ dentry->d_inode->i_ino);
+}
+
static struct dentry_operations sockfs_dentry_operations = {
.d_delete = sockfs_delete_dentry,
+ .d_dname = sockfs_dname,
};
/*
static int sock_attach_fd(struct socket *sock, struct file *file)
{
- struct qstr this;
- char name[32];
-
- this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
- this.name = name;
- this.hash = 0;
+ struct qstr name = { .name = "" };
- file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+ file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
if (unlikely(!file->f_path.dentry))
return -ENOMEM;