diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-04-21 05:08:32 +0200 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-03 01:49:29 +0200 |
commit | 6192269444ebfbfb42e23c7a6a93c76ffe4b5e51 (patch) | |
tree | ec40fbbad46725d88f2c16b11ff5976d87f497bb /fs/readdir.c | |
parent | give readdir(2)/getdents(2)/etc. uniform exclusion with lseek() (diff) | |
download | linux-6192269444ebfbfb42e23c7a6a93c76ffe4b5e51.tar.xz linux-6192269444ebfbfb42e23c7a6a93c76ffe4b5e51.zip |
introduce a parallel variant of ->iterate()
New method: ->iterate_shared(). Same arguments as in ->iterate(),
called with the directory locked only shared. Once all filesystems
switch, the old one will be gone.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/readdir.c')
-rw-r--r-- | fs/readdir.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/fs/readdir.c b/fs/readdir.c index d7308b8f6cf7..a86c6c04b9bc 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -24,15 +24,21 @@ int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); + bool shared = false; int res = -ENOTDIR; - if (!file->f_op->iterate) + if (file->f_op->iterate_shared) + shared = true; + else if (!file->f_op->iterate) goto out; res = security_file_permission(file, MAY_READ); if (res) goto out; - inode_lock(inode); + if (shared) + inode_lock_shared(inode); + else + inode_lock(inode); // res = mutex_lock_killable(&inode->i_mutex); // if (res) // goto out; @@ -40,12 +46,18 @@ int iterate_dir(struct file *file, struct dir_context *ctx) res = -ENOENT; if (!IS_DEADDIR(inode)) { ctx->pos = file->f_pos; - res = file->f_op->iterate(file, ctx); + if (shared) + res = file->f_op->iterate_shared(file, ctx); + else + res = file->f_op->iterate(file, ctx); file->f_pos = ctx->pos; fsnotify_access(file); file_accessed(file); } - inode_unlock(inode); + if (shared) + inode_unlock_shared(inode); + else + inode_unlock(inode); out: return res; } |