📄 myfsdir.c
字号:
* see fs/minix/namei.c:minix_rename() for a different example.
*
* It's not enough to just mark the various inodes as dirty. We need to
* ensure that the directory cache is updated. This turns out to be
* easy; just call d_move(old_dentry, new_dentry) to get the dentries
* updated! Or at least, that seems to be working <smile>...
*
* Returns 0 on success, -errno on failure.
*/
int myfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
int error = -ENOSYS;
// struct inode *new_inode;
// struct myfs_inode *old_pinode, *new_pinode;
/*
old_pinode = myfs_inop(old_dentry->d_inode);
new_inode = new_dentry->d_inode;
if (new_inode == NULL) {
// no file at new name; need to create a fake myfs_inode
// namebuf is big enough for <host>:port/<name>
char *namebuf;
struct myfs_inode fake_pinode;
namebuf = (char *) kmalloc(PVFSHOSTLEN + PVFSNAMELEN + 8, GFP_KERNEL);
if (namebuf == NULL) return 0;
printk((D_DIR | D_FILE), "myfs_rename, no inode for new file\n");
if ((strlen(old_pinode->name) + new_dentry->d_name.len + 2) >
PVFSHOSTLEN + PVFSDIRLEN + 7) {
// should never happen
PERROR("myfs_rename: string too long?!?\n");
kfree(namebuf);
return -ENOSYS;
}
sprintf(namebuf, "%s/%s", myfs_inop(new_dir)->name,
new_dentry->d_name.name);
fake_pinode.handle = 0;
fake_pinode.name = namebuf;
fake_pinode.super = myfs_sbp(new_dir->i_sb);
printk((D_DIR | D_FILE), "myfs_rename called, %s -> %s (new)\n",
old_pinode->name, namebuf);
error = ll_myfs_rename(old_pinode, &fake_pinode);
kfree(namebuf);
}
else {
// a file already exists with new name
new_pinode = myfs_inop(new_dentry->d_inode);
printk((D_DIR | D_FILE), "myfs_rename called, %s -> %s\n",
old_pinode->name, new_pinode->name);
error = ll_myfs_rename(old_pinode, new_pinode);
}
// Update the dcache
d_move(old_dentry, new_dentry);
*/
return error;
}
/* myfs_readdir()
*
*/
int myfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
int ret, len;
// struct myfs_dirent dbuf;
struct inode *inode;
// myfs_off_t pos;
inode = file->f_dentry->d_inode;
printk( "myfs_readdir called for 0x%lx.\n", inode->i_ino);
/*
pos = file->f_pos;
if ((ret = ll_myfs_readdir(myfs_inop(inode), &dbuf, &pos)) <= 0)
goto out; // error or EOF
len = strlen(dbuf.name);
if ((ret = filldir(dirent, dbuf.name, len, dbuf.off, dbuf.handle
#ifdef HAVE_LINUX_6_PARAM_FILLDIR
, DT_UNKNOWN // linux 2.4
#endif
)))
goto out;
// ll_myfs_readdir gives us the position to start from the next time
file->f_pos = pos;
*/
out:
return ret;
}
/* myfs_fsync(file, dentry, [datasync])
*
*/
#ifdef HAVE_LINUX_3_PARAM_FILE_FSYNC
int myfs_fsync(struct file *file, struct dentry *dentry, int datasync)
#else
int myfs_fsync(struct file *file, struct dentry *dentry)
#endif
{
int error = 0;
// struct myfs_inode *pinode;
/*
#ifdef NEED_TO_LOCK_KERNEL
lock_kernel();
#endif
pinode = myfs_inop(dentry->d_inode);
error = ll_myfs_fsync(pinode);
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
*/
return error;
}
/* myfs_dir_read()
*
* Returns -EISDIR. Just here to get the right error value back.
*/
static ssize_t myfs_dir_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
return -EISDIR;
}
/* myfs_revalidate_inode()
*
* Performs a getmeta operation to ensure that the data in the inode is
* up-to-date.
*
* QUESTION: Do we need a lock on the inode in here?
*/
int myfs_revalidate_inode(struct dentry *dentry)
{
int error = 0, len_dir, len_file;
// struct inode *inode;
// struct dentry *parent_dentry;
// struct inode *parent_inode;
// struct myfs_inode *pinode;
// struct myfs_meta meta;
// struct myfs_phys phys;
// myfs_handle_t old_handle;
// umode_t old_mode;
// char *ptr;
/*
#ifdef NEED_TO_LOCK_KERNEL
lock_kernel();
#endif
inode = dentry->d_inode;
if (inode == NULL) {
PERROR("myfs_revalidate_inode called for NULL inode\n");
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
return -EINVAL;
}
#ifdef IS_DEADDIR
if(IS_DEADDIR(dentry->d_inode))
{
PERROR("DEAD directory detected going into myfs_revalidate_inode.\n");
}
#endif
// get the parent dentry and inode -- this should be optimized later
parent_dentry = dentry->d_parent;
if (parent_dentry == NULL) {
PERROR("myfs_revalidate_inode: d_parent is NULL\n");
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
return -EINVAL;
}
parent_inode = parent_dentry->d_inode;
if (parent_inode == NULL) {
PERROR("myfs_revalidate_inode: parent inode is NULL\n");
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
return -EINVAL;
}
// reconstruct the name in the inode
len_dir = strlen(myfs_inop(parent_inode)->name);
len_file = dentry->d_name.len;
pinode = myfs_inop(inode);
// save the old handle value for debugging test
old_handle = pinode->handle;
old_mode = inode->i_mode;
// if we're not looking at the root of a file system, we need to
// rebuild the filename. it's important that pinode point to
// myfs_inop(inode) at this point in case we don't go in the "if".
if (parent_inode != inode) {
// the "1" takes into account the '/' between file and dir names
//
// if the old name is longer or of equal length, we don't realloc.
if (strlen(pinode->name) < len_file + len_dir + 1) {
struct myfs_inode *old_pinode;
// we need to reallocate the myfs_inode structure and file name.
//
// the "2" takes into account the '/' between names and the
// trailing '\0'.
old_pinode = pinode;
pinode = (struct myfs_inode *) kmalloc(sizeof(struct myfs_inode)
+ len_dir + len_file + 2,
GFP_KERNEL);
if (pinode == NULL) {
PERROR("myfs_revalidate_inode: out of memory!\n");
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
return -ENOMEM;
}
*pinode = *old_pinode; // copy in all the old values
pinode->name = (int8_t *)pinode + sizeof(struct myfs_inode);
inode->u.generic_ip = pinode;
kfree(old_pinode);
}
// copy the name into the inode: copy dirname, add /, copy name
ptr = pinode->name;
strcpy(ptr, myfs_inop(parent_inode)->name);
ptr += len_dir;
*ptr = '/';
ptr++;
strcpy(ptr, dentry->d_name.name);
}
printk(D_DIR, "myfs_revalidate_inode called for %s (%ld).\n",
pinode->name, (unsigned long) pinode->handle);
// Note: the only parameter that really is used inside of ll_myfs_getmeta()
// is the file name.
error = ll_myfs_getmeta(pinode, &meta, &phys);
if (error < 0) {
printk(D_DIR,
"myfs_revalidate: ll_myfs_getmeta() failed; updating dcache\n");
// leave the dcache alone; the calling function handles cleanup
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
return error;
}
// NOTE: not doing anything with the phys for now
myfs_meta_to_inode(&meta, inode);
if (old_handle != meta.handle) {
// need to update the inode and redo the hash
printk(D_DIR,
"myfs_revalidate_inode: handle changed from %ld to %ld for %s\n",
(unsigned long) old_handle,
(unsigned long) meta.handle, pinode->name);
remove_inode_hash(inode);
inode->i_ino = meta.handle;
pinode->handle = meta.handle;
insert_inode_hash(inode);
}
if (old_mode != inode->i_mode) {
// need to update function pointers
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 {
PERROR("myfs_revalidate_inode: handle refers to something other than a file or a directory?\n");
error = -EINVAL;
}
}
#ifdef NEED_TO_LOCK_KERNEL
unlock_kernel();
#endif
*/
return error;
}
/* myfs_dentry_revalidate()
*
* A return value of "1" indicates that things are ok. A return value of "0"
* should result in the upper layers trying to prune out the dentry (bad).
*/
static int myfs_dentry_revalidate(struct dentry *dentry, int flags)
{
int ret;
printk( "myfs_dentry_revalidate called for %s.\n", dentry->d_name.name);
/*
// don't call revalidate inode if the inode isn't valid
if (dentry->d_inode == NULL) {
PERROR("myfs_dentry_revalidate: NULL inode (negative dentry) hit.\n");
return 0;
}
ret = myfs_revalidate_inode(dentry);
*/
if (ret == 0) return 1;
else return 0; /* we got an error - let it be handled elsewhere. */
}
/* myfs_meta_to_inode()
*
* Copies a myfs_meta structure's values into an inode structure.
*/
int myfs_meta_to_inode(struct myfs_meta *mbuf, struct inode *ibuf)
{
int error = 0;
/* leaving the handle/i_ino fields alone for now */
ibuf->i_mode = mbuf->mode;
ibuf->i_uid = mbuf->uid;
ibuf->i_gid = mbuf->gid;
ibuf->i_size = mbuf->size;
ibuf->i_atime = mbuf->atime;
ibuf->i_mtime = mbuf->mtime;
ibuf->i_ctime = mbuf->ctime;
ibuf->i_blksize = mbuf->blksize;
ibuf->i_blocks = mbuf->blocks;
return error;
}
/*
* Local variables:
* c-indent-level: 3
* c-basic-offset: 3
* tab-width: 3
* End:
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -