Advertisement
Guest User

[PATCH 2/2] btrfs: Cleanup llseek()

a guest
Sep 2nd, 2013
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.99 KB | None | 0 0
  1. There are multiple issues with the custom llseek implemented in btrfs
  2. for implementing SEEK_HOLE/SEEK_DATA.
  3.  
  4. 1. It takes the inode->i_mutex lock before calling
  5. generic_file_llseek(), which is unnecessary.
  6.  
  7. 2. It fails to take the filp->f_lock spinlock before modifying
  8. filp->f_pos and filp->f_version, which differs from
  9. generic_file_llseek().
  10.  
  11. 3. It does a offset > inode->i_sb->s_maxbytes check that is dead code
  12. because the the offset >= i_size_read(inode) will evaluate to true and
  13. return ENXIO whenever the former comparison evaluates to true.
  14.  
  15. 4. The switch statement tries to cover all whence values when in reality
  16. it should only care about SEEK_HOLE/SEEK_DATA. Any other cases should be
  17. passsed to generic_file_llseek().
  18.  
  19. btrfs_file_llseek() and ocfs2_file_llseek() are extremely similar and
  20. consequently, contain many of the same flaws. Li Dongyang filed a pull
  21. request with ZFSOnLinux for SEEK_HOLE/SEEK_DATA support that included a
  22. custom llseek function that appears to have been modelled after the one
  23. in ocfs2. The similarity was strong enough that it suffered from many of
  24. the same flaws, which I caught during review. I addressed the issues
  25. with his patch with one that I wrote. I decided to adapt that code to
  26. both btrfs and ocfs2 (separate patch) because a small percentage of
  27. Gentoo Linux users are affected by these flaws.
  28.  
  29. Note that #3 would have been worse had it not been for commit
  30. 48802c8ae2a9d618ec734a61283d645ad527e06c by Jeff Liu at Oracle. Prior to
  31. his commit, btrfs llseek() would permit seeking up to the maximum file
  32. size possible on the btrfs filesystem, even when it is past the end of
  33. the file. Seeking beyond that (if possible), would return EINVAL instead
  34. of ENXIO. That was the same behavior that the ocfs2 llseek had.
  35. corrected that issue. However, the ocfs2 code was not fortunate enough
  36. to have had this corrected at that time.
  37.  
  38. Signed-off-by: Richard Yao <ryao@gentoo.org>
  39. ---
  40. fs/btrfs/file.c | 49 ++++++++++++++++++++-----------------------------
  41. 1 file changed, 20 insertions(+), 29 deletions(-)
  42.  
  43. diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
  44. index 4205ba7..1f437d8 100644
  45. --- a/fs/btrfs/file.c
  46. +++ b/fs/btrfs/file.c
  47. @@ -2400,48 +2400,39 @@ out:
  48. return ret;
  49. }
  50.  
  51. -static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence)
  52. +static loff_t btrfs_file_llseek(struct file *filp, loff_t offset, int whence)
  53. {
  54. - struct inode *inode = file->f_mapping->host;
  55. - int ret;
  56. + if (whence == SEEK_DATA || whence == SEEK_HOLE) {
  57. + struct inode *inode = filp->f_mapping->host;
  58. + int ret;
  59. +
  60. + if (offset < 0 && !(filp->f_mode & FMODE_UNSIGNED_OFFSET))
  61. + return -EINVAL;
  62.  
  63. - mutex_lock(&inode->i_mutex);
  64. - switch (whence) {
  65. - case SEEK_END:
  66. - case SEEK_CUR:
  67. - offset = generic_file_llseek(file, offset, whence);
  68. - goto out;
  69. - case SEEK_DATA:
  70. - case SEEK_HOLE:
  71. if (offset >= i_size_read(inode)) {
  72. - mutex_unlock(&inode->i_mutex);
  73. return -ENXIO;
  74. }
  75.  
  76. + mutex_lock(&inode->i_mutex);
  77. ret = find_desired_extent(inode, &offset, whence);
  78. + mutex_unlock(&inode->i_mutex);
  79. +
  80. if (ret) {
  81. - mutex_unlock(&inode->i_mutex);
  82. return ret;
  83. }
  84. - }
  85.  
  86. - if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET)) {
  87. - offset = -EINVAL;
  88. - goto out;
  89. - }
  90. - if (offset > inode->i_sb->s_maxbytes) {
  91. - offset = -EINVAL;
  92. - goto out;
  93. - }
  94. + if (offset != filp->f_pos) {
  95. + spin_lock(&filp->f_lock);
  96. + filp->f_pos = offset;
  97. + filp->f_version = 0;
  98. + spin_unlock(&filp->f_lock);
  99. + }
  100.  
  101. - /* Special lock needed here? */
  102. - if (offset != file->f_pos) {
  103. - file->f_pos = offset;
  104. - file->f_version = 0;
  105. + return offset;
  106. }
  107. -out:
  108. - mutex_unlock(&inode->i_mutex);
  109. - return offset;
  110. +
  111. + return generic_file_llseek(filp, offset, whence);
  112. +
  113. }
  114.  
  115. const struct file_operations btrfs_file_operations = {
  116. --
  117. 1.8.1.5
  118.  
  119. --
  120. To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
  121. the body of a message to majordomo@vger.kernel.org
  122. More majordomo info at http://vger.kernel.org/majordomo-info.html
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement