diff options
| -rw-r--r-- | arch/parisc/hpux/fs.c | 2 | ||||
| -rw-r--r-- | fs/coda/dir.c | 19 | ||||
| -rw-r--r-- | fs/compat.c | 4 | ||||
| -rw-r--r-- | fs/exportfs/expfs.c | 2 | ||||
| -rw-r--r-- | fs/nfsd/nfs4recover.c | 14 | ||||
| -rw-r--r-- | fs/readdir.c | 15 | ||||
| -rw-r--r-- | include/linux/fs.h | 9 |
7 files changed, 47 insertions, 18 deletions
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index fc2cbee86e34..eca8230267cc 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c | |||
| @@ -129,7 +129,7 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i | |||
| 129 | error = buf.error; | 129 | error = buf.error; |
| 130 | lastdirent = buf.previous; | 130 | lastdirent = buf.previous; |
| 131 | if (lastdirent) { | 131 | if (lastdirent) { |
| 132 | if (put_user(arg.file->f_pos, &lastdirent->d_off)) | 132 | if (put_user(buf.ctx.pos, &lastdirent->d_off)) |
| 133 | error = -EFAULT; | 133 | error = -EFAULT; |
| 134 | else | 134 | else |
| 135 | error = count - buf.count; | 135 | error = count - buf.count; |
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index b7d3a05c062c..fc66861b3598 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
| @@ -391,8 +391,7 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) | |||
| 391 | if (!host_file->f_op) | 391 | if (!host_file->f_op) |
| 392 | return -ENOTDIR; | 392 | return -ENOTDIR; |
| 393 | 393 | ||
| 394 | if (host_file->f_op->readdir) | 394 | if (host_file->f_op->readdir) { |
| 395 | { | ||
| 396 | /* potemkin case: we were handed a directory inode. | 395 | /* potemkin case: we were handed a directory inode. |
| 397 | * We can't use vfs_readdir because we have to keep the file | 396 | * We can't use vfs_readdir because we have to keep the file |
| 398 | * position in sync between the coda_file and the host_file. | 397 | * position in sync between the coda_file and the host_file. |
| @@ -410,8 +409,20 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir) | |||
| 410 | 409 | ||
| 411 | coda_file->f_pos = host_file->f_pos; | 410 | coda_file->f_pos = host_file->f_pos; |
| 412 | mutex_unlock(&host_inode->i_mutex); | 411 | mutex_unlock(&host_inode->i_mutex); |
| 413 | } | 412 | } else if (host_file->f_op->iterate) { |
| 414 | else /* Venus: we must read Venus dirents from a file */ | 413 | struct inode *host_inode = file_inode(host_file); |
| 414 | struct dir_context *ctx = buf; | ||
| 415 | |||
| 416 | mutex_lock(&host_inode->i_mutex); | ||
| 417 | ret = -ENOENT; | ||
| 418 | if (!IS_DEADDIR(host_inode)) { | ||
| 419 | ret = host_file->f_op->iterate(host_file, ctx); | ||
| 420 | file_accessed(host_file); | ||
| 421 | } | ||
| 422 | mutex_unlock(&host_inode->i_mutex); | ||
| 423 | |||
| 424 | coda_file->f_pos = ctx->pos; | ||
| 425 | } else /* Venus: we must read Venus dirents from a file */ | ||
| 415 | ret = coda_venus_readdir(coda_file, buf, filldir); | 426 | ret = coda_venus_readdir(coda_file, buf, filldir); |
| 416 | 427 | ||
| 417 | return ret; | 428 | return ret; |
diff --git a/fs/compat.c b/fs/compat.c index 2279b59e81f2..69ca1e301766 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -975,7 +975,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd, | |||
| 975 | error = buf.error; | 975 | error = buf.error; |
| 976 | lastdirent = buf.previous; | 976 | lastdirent = buf.previous; |
| 977 | if (lastdirent) { | 977 | if (lastdirent) { |
| 978 | if (put_user(f.file->f_pos, &lastdirent->d_off)) | 978 | if (put_user(buf.ctx.pos, &lastdirent->d_off)) |
| 979 | error = -EFAULT; | 979 | error = -EFAULT; |
| 980 | else | 980 | else |
| 981 | error = count - buf.count; | 981 | error = count - buf.count; |
| @@ -1062,7 +1062,7 @@ asmlinkage long compat_sys_getdents64(unsigned int fd, | |||
| 1062 | error = buf.error; | 1062 | error = buf.error; |
| 1063 | lastdirent = buf.previous; | 1063 | lastdirent = buf.previous; |
| 1064 | if (lastdirent) { | 1064 | if (lastdirent) { |
| 1065 | typeof(lastdirent->d_off) d_off = f.file->f_pos; | 1065 | typeof(lastdirent->d_off) d_off = buf.ctx.pos; |
| 1066 | if (__put_user_unaligned(d_off, &lastdirent->d_off)) | 1066 | if (__put_user_unaligned(d_off, &lastdirent->d_off)) |
| 1067 | error = -EFAULT; | 1067 | error = -EFAULT; |
| 1068 | else | 1068 | else |
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 7cb190426cec..6c8ef1dd4bdf 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
| @@ -272,7 +272,7 @@ static int get_name(const struct path *path, char *name, struct dentry *child) | |||
| 272 | goto out; | 272 | goto out; |
| 273 | 273 | ||
| 274 | error = -EINVAL; | 274 | error = -EINVAL; |
| 275 | if (!file->f_op->readdir) | 275 | if (!file->f_op->readdir && !file->f_op->iterate) |
| 276 | goto out_close; | 276 | goto out_close; |
| 277 | 277 | ||
| 278 | buffer.name = name; | 278 | buffer.name = name; |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 4f8cc6ba7c28..2fa2e2eb190b 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
| @@ -240,11 +240,16 @@ struct name_list { | |||
| 240 | struct list_head list; | 240 | struct list_head list; |
| 241 | }; | 241 | }; |
| 242 | 242 | ||
| 243 | struct nfs4_dir_ctx { | ||
| 244 | struct dir_context ctx; | ||
| 245 | struct list_head names; | ||
| 246 | }; | ||
| 247 | |||
| 243 | static int | 248 | static int |
| 244 | nfsd4_build_namelist(void *arg, const char *name, int namlen, | 249 | nfsd4_build_namelist(void *arg, const char *name, int namlen, |
| 245 | loff_t offset, u64 ino, unsigned int d_type) | 250 | loff_t offset, u64 ino, unsigned int d_type) |
| 246 | { | 251 | { |
| 247 | struct list_head *names = arg; | 252 | struct nfs4_dir_ctx *ctx = arg; |
| 248 | struct name_list *entry; | 253 | struct name_list *entry; |
| 249 | 254 | ||
| 250 | if (namlen != HEXDIR_LEN - 1) | 255 | if (namlen != HEXDIR_LEN - 1) |
| @@ -254,7 +259,7 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen, | |||
| 254 | return -ENOMEM; | 259 | return -ENOMEM; |
| 255 | memcpy(entry->name, name, HEXDIR_LEN - 1); | 260 | memcpy(entry->name, name, HEXDIR_LEN - 1); |
| 256 | entry->name[HEXDIR_LEN - 1] = '\0'; | 261 | entry->name[HEXDIR_LEN - 1] = '\0'; |
| 257 | list_add(&entry->list, names); | 262 | list_add(&entry->list, &ctx->names); |
| 258 | return 0; | 263 | return 0; |
| 259 | } | 264 | } |
| 260 | 265 | ||
| @@ -263,10 +268,7 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) | |||
| 263 | { | 268 | { |
| 264 | const struct cred *original_cred; | 269 | const struct cred *original_cred; |
| 265 | struct dentry *dir = nn->rec_file->f_path.dentry; | 270 | struct dentry *dir = nn->rec_file->f_path.dentry; |
| 266 | struct { | 271 | struct nfs4_dir_ctx ctx; |
| 267 | struct dir_context ctx; | ||
| 268 | struct list_head names; | ||
| 269 | } ctx; | ||
| 270 | int status; | 272 | int status; |
| 271 | 273 | ||
| 272 | status = nfs4_save_creds(&original_cred); | 274 | status = nfs4_save_creds(&original_cred); |
diff --git a/fs/readdir.c b/fs/readdir.c index 5b620a2b45e6..5d6578affbbf 100644 --- a/fs/readdir.c +++ b/fs/readdir.c | |||
| @@ -24,7 +24,7 @@ int iterate_dir(struct file *file, struct dir_context *ctx) | |||
| 24 | { | 24 | { |
| 25 | struct inode *inode = file_inode(file); | 25 | struct inode *inode = file_inode(file); |
| 26 | int res = -ENOTDIR; | 26 | int res = -ENOTDIR; |
| 27 | if (!file->f_op || !file->f_op->readdir) | 27 | if (!file->f_op || (!file->f_op->readdir && !file->f_op->iterate)) |
| 28 | goto out; | 28 | goto out; |
| 29 | 29 | ||
| 30 | res = security_file_permission(file, MAY_READ); | 30 | res = security_file_permission(file, MAY_READ); |
| @@ -37,7 +37,14 @@ int iterate_dir(struct file *file, struct dir_context *ctx) | |||
| 37 | 37 | ||
| 38 | res = -ENOENT; | 38 | res = -ENOENT; |
| 39 | if (!IS_DEADDIR(inode)) { | 39 | if (!IS_DEADDIR(inode)) { |
| 40 | res = file->f_op->readdir(file, ctx, ctx->actor); | 40 | if (file->f_op->iterate) { |
| 41 | ctx->pos = file->f_pos; | ||
| 42 | res = file->f_op->iterate(file, ctx); | ||
| 43 | file->f_pos = ctx->pos; | ||
| 44 | } else { | ||
| 45 | res = file->f_op->readdir(file, ctx, ctx->actor); | ||
| 46 | ctx->pos = file->f_pos; | ||
| 47 | } | ||
| 41 | file_accessed(file); | 48 | file_accessed(file); |
| 42 | } | 49 | } |
| 43 | mutex_unlock(&inode->i_mutex); | 50 | mutex_unlock(&inode->i_mutex); |
| @@ -214,7 +221,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, | |||
| 214 | error = buf.error; | 221 | error = buf.error; |
| 215 | lastdirent = buf.previous; | 222 | lastdirent = buf.previous; |
| 216 | if (lastdirent) { | 223 | if (lastdirent) { |
| 217 | if (put_user(f.file->f_pos, &lastdirent->d_off)) | 224 | if (put_user(buf.ctx.pos, &lastdirent->d_off)) |
| 218 | error = -EFAULT; | 225 | error = -EFAULT; |
| 219 | else | 226 | else |
| 220 | error = count - buf.count; | 227 | error = count - buf.count; |
| @@ -296,7 +303,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, | |||
| 296 | error = buf.error; | 303 | error = buf.error; |
| 297 | lastdirent = buf.previous; | 304 | lastdirent = buf.previous; |
| 298 | if (lastdirent) { | 305 | if (lastdirent) { |
| 299 | typeof(lastdirent->d_off) d_off = f.file->f_pos; | 306 | typeof(lastdirent->d_off) d_off = buf.ctx.pos; |
| 300 | if (__put_user(d_off, &lastdirent->d_off)) | 307 | if (__put_user(d_off, &lastdirent->d_off)) |
| 301 | error = -EFAULT; | 308 | error = -EFAULT; |
| 302 | else | 309 | else |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 643e5b6cbaf5..b9641ae68da8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1508,7 +1508,15 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); | |||
| 1508 | typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); | 1508 | typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); |
| 1509 | struct dir_context { | 1509 | struct dir_context { |
| 1510 | filldir_t actor; | 1510 | filldir_t actor; |
| 1511 | loff_t pos; | ||
| 1511 | }; | 1512 | }; |
| 1513 | |||
| 1514 | static inline bool dir_emit(struct dir_context *ctx, | ||
| 1515 | const char *name, int namelen, | ||
| 1516 | u64 ino, unsigned type) | ||
| 1517 | { | ||
| 1518 | return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0; | ||
| 1519 | } | ||
| 1512 | struct block_device_operations; | 1520 | struct block_device_operations; |
| 1513 | 1521 | ||
| 1514 | /* These macros are for out of kernel modules to test that | 1522 | /* These macros are for out of kernel modules to test that |
| @@ -1525,6 +1533,7 @@ struct file_operations { | |||
| 1525 | ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); | 1533 | ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); |
| 1526 | ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); | 1534 | ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); |
| 1527 | int (*readdir) (struct file *, void *, filldir_t); | 1535 | int (*readdir) (struct file *, void *, filldir_t); |
| 1536 | int (*iterate) (struct file *, struct dir_context *); | ||
| 1528 | unsigned int (*poll) (struct file *, struct poll_table_struct *); | 1537 | unsigned int (*poll) (struct file *, struct poll_table_struct *); |
| 1529 | long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); | 1538 | long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); |
| 1530 | long (*compat_ioctl) (struct file *, unsigned int, unsigned long); | 1539 | long (*compat_ioctl) (struct file *, unsigned int, unsigned long); |
