📄 myfsdir.c
字号:
#include "common.h"
#include "mytypes.h"
extern struct myfs_inode *myfs_inop(struct inode *ino);
/* dentry ops */
static int myfs_dentry_revalidate(struct dentry *de, int);
/* dir inode-ops */
static struct dentry *myfs_lookup(struct inode *dir, struct dentry *target);
static int myfs_unlink(struct inode *dir_inode, struct dentry *entry);
static int myfs_mkdir(struct inode *dir_inode, struct dentry *entry, int mode);
static int myfs_rmdir(struct inode *dir_inode, struct dentry *entry);
int myfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry);
int myfs_revalidate_inode(struct dentry *dentry);
/* dir file-ops */
static int myfs_readdir(struct file *file, void *dirent, filldir_t filldir);
static ssize_t myfs_dir_read(struct file *file, char *buf, size_t count,
loff_t *ppos);
struct dentry_operations myfs_dentry_operations =
{
d_revalidate: myfs_dentry_revalidate
};
struct inode_operations myfs_dir_inode_operations =
{
/* put this in right later... myfs_notify_change */
/* &myfs_dir_operations, */
// create: myfs_file_create, /* create TODO: DOES THIS NEED TO BE HERE? */
lookup: myfs_lookup, /* lookup */
unlink: myfs_unlink, /* unlink called on parent directory to unlink a file */
mkdir: myfs_mkdir, /* mkdir */
rmdir: myfs_rmdir, /* rmdir */
rename: myfs_rename, /* rename */
revalidate: myfs_revalidate_inode, /* revalidate */
// setattr: myfs_notify_change
};
struct file_operations myfs_dir_operations = {
read: myfs_dir_read, /* read -- returns -EISDIR */
readdir: myfs_readdir /* readdir */
};
/* inode operations for directories */
/* myfs_lookup(dir, entry)
*
* Notes:
* - name to look for is in the entry (entry->d_name.name, entry->d_name.len)
* - dir is the directory in which we are doing the lookup
*
* Behavior:
* - call ll_myfs_lookup to get a handle
* - grab an inode for the new handle
* - fill in the inode metadata
* - add the dentry/inode pair into the dcache
* - (optionally) set up pointer to new dentry functions
*
* Returns NULL pretty much all the time. I know, this seems really
* screwed up, but the ext2 fs seems to be doing the same thing...
*/
static struct dentry *myfs_lookup(struct inode *dir, struct dentry *entry)
{
int error = 0, len_dir, len_file;
// struct myfs_inode *pinode;
// struct myfs_meta meta;
// struct inode *inode = NULL;
// char *ptr;
printk("myfs_lookup called on %ld for %s\n", dir->i_ino, entry->d_name.name);
printk("name might be %s/%s\n", myfs_inop(dir)->name, entry->d_name.name);
/* len_dir = strlen(myfs_inop(dir)->name);
len_file = entry->d_name.len;
if ((pinode = (struct myfs_inode *) kmalloc(sizeof(struct myfs_inode)
+ len_dir + len_file + 2, GFP_KERNEL)) == NULL){
return NULL;
}
// fill in myfs_inode name field first
pinode->name = (int8_t *)pinode + sizeof(struct myfs_inode);
ptr = pinode->name;
strcpy(ptr, myfs_inop(dir)->name);
ptr += len_dir;
*ptr = '/';
ptr++;
strcpy(ptr, entry->d_name.name);
// do the lookup, grabs metadata
error = ll_myfs_lookup(myfs_sbp(dir->i_sb), pinode->name,
len_dir + len_file + 1, &meta);
if (error < 0 && error != -ENOENT) {
// real error
kfree(pinode);
return ERR_PTR(error);
}
if (error == -ENOENT) {
// no file found; need to insert NULL inode so that create calls
// can work correctly (or so says Gooch)
entry->d_time = 0;
entry->d_op = &myfs_dentry_operations;
d_add(entry, NULL);
kfree(pinode);
return NULL;
}
if ((inode = iget(dir->i_sb, meta.handle)) == NULL) {
// let's drop the dentry here...
kfree(pinode);
return ERR_PTR(-ENOMEM);
}
// fill in inode structure, remainder of myfs_inode
pinode->handle = inode->i_ino;
pinode->super = myfs_sbp(inode->i_sb);
myfs_meta_to_inode(&meta, inode);
inode->u.generic_ip = pinode;
entry->d_time = 0;
entry->d_op = &myfs_dentry_operations;
printk(D_DIR, "saved name is %s\n", myfs_inop(inode)->name);
if (S_ISDIR(inode->i_mode)) {
inode->i_op = &myfs_dir_inode_operations;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
inode->i_fop = &myfs_dir_operations;
#endif
}
else if (S_ISREG(inode->i_mode)) {
inode->i_op = &myfs_file_inode_operations;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
inode->i_fop = &myfs_file_operations;
#endif
#ifdef HAVE_LINUX_STRUCT_ADDRESS_SPACE_OPERATIONS
inode->i_data.a_ops = &myfs_file_aops;
#endif
}
else {
inode->i_op = NULL;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
inode->i_fop = NULL;
#endif
}
d_add(entry, inode);
*/
return NULL;
}
/* myfs_mkdir()
*
* Called on parent directory with dentry of directory to create.
*
* This is pretty much a carbon copy of myfs_file_create().
*/
static int myfs_mkdir(struct inode *dir, struct dentry *entry, int mode)
{
int error = 0, len_dir, len_file;
// struct inode *inode;
// struct myfs_meta meta;
// struct myfs_inode *pinode;
// char *ptr;
printk("myfs_mkdir called on %ld for %s\n", dir->i_ino, entry->d_name.name);
/* len_dir = strlen(myfs_inop(dir)->name);
len_file = entry->d_name.len;
if ((pinode = (struct myfs_inode *) kmalloc(sizeof(struct myfs_inode)
+ len_dir + len_file + 2, GFP_KERNEL)) == NULL){
return -ENOMEM;
}
// build myfs_inode name field first
pinode->name = (int8_t *)pinode + sizeof(struct myfs_inode);
ptr = pinode->name;
strcpy(ptr, myfs_inop(dir)->name);
ptr += len_dir;
*ptr = '/';
ptr++;
strcpy(ptr, entry->d_name.name);
// do the create
meta.valid = V_MODE | V_UID | V_GID | V_TIMES;
meta.uid = current->fsuid;
meta.gid = current->fsgid;
meta.mode = mode;
meta.mtime = meta.atime = meta.ctime = CURRENT_TIME;
printk(D_DIR, "myfs_mkdir calling ll_myfs_mkdir\n");
if ((error = ll_myfs_mkdir(myfs_sbp(dir->i_sb), pinode->name,
len_dir + len_file + 1, &meta )) < 0)
{
kfree(pinode);
return error;
}
// do a lookup so we can fill in the inode
printk(D_DIR, "myfs_mkdir calling ll_myfs_lookup\n");
if ((error = ll_myfs_lookup(myfs_sbp(dir->i_sb), pinode->name,
len_dir + len_file + 1, &meta)) < 0)
{
kfree(pinode);
return error;
}
// fill in inode structure and remainder of myfs_inode
if ((inode = iget(dir->i_sb, meta.handle)) == NULL) {
kfree(pinode);
return -ENOMEM;
}
pinode->handle = inode->i_ino;
pinode->super = myfs_sbp(inode->i_sb);
myfs_meta_to_inode(&meta, inode);
inode->u.generic_ip = pinode;
d_instantiate(entry, inode); // do I know what this does? nope!
printk(D_DIR, "saved name is %s\n", myfs_inop(inode)->name);
if (S_ISDIR(inode->i_mode)) {
inode->i_op = &myfs_dir_inode_operations;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
inode->i_fop = &myfs_dir_operations;
#endif
}
else if (S_ISREG(inode->i_mode)) {
inode->i_op = &myfs_file_inode_operations;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
inode->i_fop = &myfs_file_operations;
#endif
#ifdef HAVE_LINUX_STRUCT_ADDRESS_SPACE_OPERATIONS
inode->i_data.a_ops = &myfs_file_aops;
#endif
}
else {
inode->i_op = NULL;
#ifdef HAVE_LINUX_STRUCT_INODE_I_FOP
inode->i_fop = NULL;
#endif
}
*/
return error;
}
/* myfs_unlink(dir, entry)
*
* Called on parent directory with dentry of file to unlink. We call
* d_delete(entry) when done to take the dentry out of the cache. This
* call also frees the inode associated with the unlinked file.
*
*/
int myfs_unlink(struct inode *dir, struct dentry *entry)
{
int error = 0;
printk("myfs_unlink called on %ld for %s\n", dir->i_ino, entry->d_name.name);
/*
if (entry->d_inode == NULL) {
// negative dentry ?!?
PERROR("myfs_unlink: negative dentry?\n");
// TODO: should look up the file?
return -ENOENT;
}
if (entry->d_inode->i_nlink == 0) {
PERROR("myfs_unlink: deleting nonexistent file?\n");
}
error = ll_myfs_unlink(myfs_inop(entry->d_inode));
if (error == 0)
{
entry->d_inode->i_nlink--;
#ifndef HAVE_LINUX_STRUCT_ADDRESS_SPACE_OPERATIONS
// We should only do a d_delete() on 2.2 kernels. i
// There isn't a good autoconf test to detect this yet,
// so we use this ifndef.
d_delete(entry); // this also frees the inode
#endif
}
*/
return error;
}
/* myfs_rmdir()
*
* Called on parent directory with dentry of directory to remove.
*
* TODO: I'm not so sure that I know everything this call should be
* doing; look at minix/namei.c:minix_rmdir() for some possible ideas.
*/
int myfs_rmdir(struct inode *dir, struct dentry *entry)
{
int error = 0;
/*
#ifdef HAVE_D_UNHASHED
if (!d_unhashed(entry))
#else
if (!list_empty(&entry->d_hash))
#endif // HAVE_D_UNHASHED
{
printk(D_DIR, "myfs_rmdir failing because dir (%s) is busy.\n",
entry->d_name.name);
return -EBUSY;
}
printk(D_DIR, "myfs_rmdir called on %ld for %s\n", dir->i_ino,
entry->d_name.name);
if (entry->d_inode == NULL) {
// negative dentry ?!?
PERROR("myfs_rmdir: negative dentry?\n");
// TODO: should look up the file?
return -ENOENT;
}
if (entry->d_inode->i_nlink == 0) {
PERROR("myfs_rmdir: deleting nonexistent directory?\n");
}
error = ll_myfs_rmdir(myfs_inop(entry->d_inode));
if (error == 0)
{
entry->d_inode->i_nlink--;
#ifndef HAVE_LINUX_STRUCT_ADDRESS_SPACE_OPERATIONS
// We should only do a d_delete() on 2.2 kernels. i
// There isn't a good autoconf test to detect this yet,
// so we use this ifndef.
d_delete(entry); // this also frees the inode
#endif
}
*/
return error;
}
/* myfs_rename(old_dir, old_dentry, new_dir, new_dentry)
*
* PARAMETERS:
* old_dir - inode of parent directory of file/dir to be moved
* new_dir - inode of parent directory of destination
* old_dentry - dentry referring to the file/dir to move
* new_dentry - dentry referring to the destination; inode might or
* might not be available.
*
* NOTES:
* If the target name already exists, there will be a valid inode in the
* new_dentry. If the inode pointer is NULL, then there is nothing
* referred to by that name.
*
* Also need to update the dcache and such to take changes into account!
*
* see fs/nfs/dir.c:nfs_rename() for an example.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -