Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | /* * fs/libfs.c * Library for filesystems writers. */ #include <linux/pagemap.h> #include <linux/smp_lock.h> int simple_statfs(struct super_block *sb, struct statfs *buf) { buf->f_type = sb->s_magic; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_namelen = NAME_MAX; return 0; } /* * Lookup the data. This is trivial - if the dentry didn't already * exist, we know it is negative. */ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry) { d_add(dentry, NULL); return NULL; } int simple_sync_file(struct file * file, struct dentry *dentry, int datasync) { return 0; } int dcache_dir_open(struct inode *inode, struct file *file) { static struct qstr cursor_name = {len:1, name:"."}; file->private_data = d_alloc(file->f_dentry, &cursor_name); return file->private_data ? 0 : -ENOMEM; } int dcache_dir_close(struct inode *inode, struct file *file) { dput(file->private_data); return 0; } loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) { down(&file->f_dentry->d_inode->i_sem); switch (origin) { case 1: offset += file->f_pos; case 0: if (offset >= 0) break; default: up(&file->f_dentry->d_inode->i_sem); return -EINVAL; } if (offset != file->f_pos) { file->f_pos = offset; if (file->f_pos >= 2) { struct list_head *p; struct dentry *cursor = file->private_data; loff_t n = file->f_pos - 2; spin_lock(&dcache_lock); p = file->f_dentry->d_subdirs.next; while (n && p != &file->f_dentry->d_subdirs) { struct dentry *next; next = list_entry(p, struct dentry, d_child); if (!list_empty(&next->d_hash) && next->d_inode) n--; p = p->next; } list_del(&cursor->d_child); list_add_tail(&cursor->d_child, p); spin_unlock(&dcache_lock); } } up(&file->f_dentry->d_inode->i_sem); return offset; } /* * Directory is locked and all positive dentries in it are safe, since * for ramfs-type trees they can't go away without unlink() or rmdir(), * both impossible due to the lock on directory. */ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_dentry; struct dentry *cursor = filp->private_data; struct list_head *p, *q = &cursor->d_child; ino_t ino; int i = filp->f_pos; switch (i) { case 0: ino = dentry->d_inode->i_ino; if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) break; filp->f_pos++; i++; /* fallthrough */ case 1: ino = parent_ino(dentry); if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) break; filp->f_pos++; i++; /* fallthrough */ default: spin_lock(&dcache_lock); if (filp->f_pos == 2) { list_del(q); list_add(q, &dentry->d_subdirs); } for (p=q->next; p != &dentry->d_subdirs; p=p->next) { struct dentry *next; next = list_entry(p, struct dentry, d_child); if (list_empty(&next->d_hash) || !next->d_inode) continue; spin_unlock(&dcache_lock); if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, DT_UNKNOWN) < 0) return 0; spin_lock(&dcache_lock); /* next is still alive */ list_del(q); list_add(q, p); p = q; filp->f_pos++; } spin_unlock(&dcache_lock); } return 0; } ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos) { return -EISDIR; } struct file_operations simple_dir_operations = { open: dcache_dir_open, release: dcache_dir_close, llseek: dcache_dir_lseek, read: generic_read_dir, readdir: dcache_readdir, }; struct inode_operations simple_dir_inode_operations = { lookup: simple_lookup, }; |