/** * \<\<private\>\> Helper callback method when filling the entry's * pathname The entry fills in its name and the '/' as prefix to the * current end of the buffer. * * @param *self - pointer to this instance * @param *buf_data - buffer data that contain pointer to the buffer and * its current length. */ static void tcmi_ctlfs_add_path(struct tcmi_ctlfs_entry *self, void *buf_data) { struct { char *buffer; int length; } *buf = buf_data; int cur = strlen(tcmi_ctlfs_entry_name(self)); mdbg(INFO4, "Adding.. %s, buffer length=%d", tcmi_ctlfs_entry_name(self), buf->length); /* back up enough to print entry name with '/' prefix */ buf->length -= cur; strncpy(buf->buffer + buf->length, tcmi_ctlfs_entry_name(self), cur); *(buf->buffer + --(buf->length)) = '/'; mdbg(INFO4, "New buffer length=%d", buf->length); }
/** * \<\<private\>\> This private method is responsible for freeing any * resources the entry is currently using(currently nothing). When * possible the child class is also notified. The instance is * eventually destroyed. * * @param *self - pointer to this instance * @return 0 */ static inline void tcmi_ctlfs_entry_release(struct tcmi_ctlfs_entry *self) { mdbg(INFO4, "entry '%s' is being freed(%p)", tcmi_ctlfs_entry_name(self), self); /* free child class instance data? */ if (self->entry_ops && self->entry_ops->entry_release) { self->entry_ops->entry_release(self); } kfree(self); }
/** * \<\<public\>\> This method is used when initializing a new entry. * It follows these steps: * * - converts the nameformat string and the args into a regular string * This will be the name assigned to the dentry * - checks whether we have a valid parent directory * - check whether an entry with the same name already exists * in the parent directory entry(if so, an error is returned) * - creates a new inode with the specified super block and operations * - creates a new dentry associated with the inode. * - sets a entry_operations specific to this particular entry type * This supports polymorphism. * * @param *self - pointer to this instance * @param *parent - pointer to the parent entry - has to be a directory * @param *mode - file type and access rights for the inode * @param *entry_ops - custom operations of the child class * @param *i_ops - inode operations * @param *f_ops - file operations(also stored in the new inode) * @param namefmt - nameformat string (printf style) * @param args - arguments to the format string * @return 0 upon success */ int tcmi_ctlfs_entry_init(struct tcmi_ctlfs_entry *self, struct tcmi_ctlfs_entry *parent, mode_t mode, struct tcmi_ctlfs_ops *entry_ops, const struct inode_operations *i_ops, const struct file_operations *f_ops, const char namefmt[], va_list args) { struct inode *dir; struct inode *inode; vsnprintf(self->name, sizeof(self->name), namefmt, args); mdbg(INFO4, "Initializing a new tcmi_ctlfs_entry, '%s'(%p)", self->name, self); if (!parent) { mdbg(ERR4, "Can't initialized new entry '%s', no parent specified! ", self->name); goto exit0; } mdbg(INFO4, "Parent entry='%s'", tcmi_ctlfs_entry_name(parent)); /* */ dir = parent->dentry->d_inode; if (!S_ISDIR(dir->i_mode)) { mdbg(ERR3, "Can't initialize new entry '%s', parent entry is not a directory!", self->name); goto exit0; } /* check parent for an entry with 'name' */ if (tcmi_ctlfs_entry_exists(parent, self->name)) { mdbg(ERR3,"Can't initialize new entry '%s', parent entry contains an entry of the same name!", self->name); goto exit0; } /* allocate a new inode */ if (!(inode = tcmi_ctlfs_get_inode(dir, dir->i_sb, mode, i_ops, f_ops))) { mdbg(ERR3, "Failed to allocate an inode for '%s'", self->name); goto exit0; } /* allocate a new dentry, associated with the inode */ if (tcmi_ctlfs_entry_alloc_dentry(self, parent, inode)) { mdbg(ERR3, "Failed to allocate a new dentry for %s", self->name); goto exit1; } /* Custom operations of the child class */ self->entry_ops = entry_ops; d_set_d_op(self->dentry, self->dentry->d_op); //Fix for new kernel, this function set dentry->flags according to dentry->op | by Jiri Rakosnik return 0; /* error handling */ exit1: iput(inode); exit0: return -ENOSPC; }
/** * \<\<private\>\> Helper callback function when calculating entry * pathname length. * * @param *self - pointer to this instance * @param *curr_length - pointer to the current length */ static void tcmi_ctlfs_add_length(struct tcmi_ctlfs_entry *self, void *curr_length) { /* + 1 accounts for '/' */ (*((int *)curr_length)) += strlen(tcmi_ctlfs_entry_name(self)) + 1; }
/** * \<\<private\>\> This method is used to free the data associated with the * symlink. The target entry's reference is decremented as * the symlink doesn't need the target entry anymore. * * @param *entry - points to the symlink that is to be freed * @return 0 upon success */ static void tcmi_ctlfs_symlink_release(struct tcmi_ctlfs_entry *entry) { struct tcmi_ctlfs_symlink *symlink = TCMI_CTLFS_SYMLINK(entry); mdbg(INFO3, "Target entry '%s' released", tcmi_ctlfs_entry_name(symlink->target_entry)); tcmi_ctlfs_entry_put(symlink->target_entry); }