patch-2.4.19 linux-2.4.19/fs/readdir.c
Next file: linux-2.4.19/fs/reiserfs/bitmap.c
Previous file: linux-2.4.19/fs/read_write.c
Back to the patch index
Back to the overall index
- Lines: 167
- Date:
Fri Aug 2 17:39:45 2002
- Orig file:
linux-2.4.18/fs/readdir.c
- Orig date:
Sun Aug 12 14:59:08 2001
diff -urN linux-2.4.18/fs/readdir.c linux-2.4.19/fs/readdir.c
@@ -33,6 +33,64 @@
return res;
}
+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;
+}
+
+int dcache_dir_fsync(struct file * file, struct dentry *dentry, int datasync)
+{
+ return 0;
+}
+
/*
* 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(),
@@ -41,62 +99,65 @@
int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- int i;
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;
- i = filp->f_pos;
switch (i) {
case 0:
- if (filldir(dirent, ".", 1, i, dentry->d_inode->i_ino, DT_DIR) < 0)
+ ino = dentry->d_inode->i_ino;
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
break;
- i++;
filp->f_pos++;
+ i++;
/* fallthrough */
case 1:
- if (filldir(dirent, "..", 2, i, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
+ spin_lock(&dcache_lock);
+ ino = dentry->d_parent->d_inode->i_ino;
+ spin_unlock(&dcache_lock);
+ if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
break;
- i++;
filp->f_pos++;
+ i++;
/* fallthrough */
- default: {
- struct list_head *list;
- int j = i-2;
-
+ default:
spin_lock(&dcache_lock);
- list = dentry->d_subdirs.next;
-
- for (;;) {
- if (list == &dentry->d_subdirs) {
- spin_unlock(&dcache_lock);
- return 0;
- }
- if (!j)
- break;
- j--;
- list = list->next;
+ if (filp->f_pos == 2) {
+ list_del(q);
+ list_add(q, &dentry->d_subdirs);
}
-
- while(1) {
- struct dentry *de = list_entry(list, struct dentry, d_child);
-
- if (!list_empty(&de->d_hash) && de->d_inode) {
- spin_unlock(&dcache_lock);
- if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0)
- break;
- spin_lock(&dcache_lock);
- }
- filp->f_pos++;
- list = list->next;
- if (list != &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);
- break;
+ 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;
}
+struct file_operations dcache_dir_ops = {
+ open: dcache_dir_open,
+ release: dcache_dir_close,
+ llseek: dcache_dir_lseek,
+ read: generic_read_dir,
+ readdir: dcache_readdir,
+ fsync: dcache_dir_fsync,
+};
+
/*
* Traditional linux readdir() handling..
*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)