diff options
| -rw-r--r-- | fs/overlayfs/dir.c | 37 |
1 files changed, 33 insertions, 4 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index bfabc65fdc74..0c5e79966957 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
| @@ -150,12 +150,39 @@ static int ovl_dir_getattr(const struct path *path, struct kstat *stat, | |||
| 150 | type = ovl_path_real(dentry, &realpath); | 150 | type = ovl_path_real(dentry, &realpath); |
| 151 | old_cred = ovl_override_creds(dentry->d_sb); | 151 | old_cred = ovl_override_creds(dentry->d_sb); |
| 152 | err = vfs_getattr(&realpath, stat, request_mask, flags); | 152 | err = vfs_getattr(&realpath, stat, request_mask, flags); |
| 153 | revert_creds(old_cred); | ||
| 154 | if (err) | 153 | if (err) |
| 155 | return err; | 154 | goto out; |
| 155 | |||
| 156 | /* | ||
| 157 | * When all layers are on the same fs, use the copy-up-origin st_ino, | ||
| 158 | * which is persistent, unique and constant across copy up. | ||
| 159 | * | ||
| 160 | * Otherwise the pair {real st_ino; overlay st_dev} is not unique, so | ||
| 161 | * use the non persistent overlay st_ino. | ||
| 162 | */ | ||
| 163 | if (ovl_same_sb(dentry->d_sb)) { | ||
| 164 | if (OVL_TYPE_ORIGIN(type)) { | ||
| 165 | struct kstat lowerstat; | ||
| 166 | |||
| 167 | ovl_path_lower(dentry, &realpath); | ||
| 168 | err = vfs_getattr(&realpath, &lowerstat, | ||
| 169 | STATX_INO, flags); | ||
| 170 | if (err) | ||
| 171 | goto out; | ||
| 172 | |||
| 173 | WARN_ON_ONCE(stat->dev != lowerstat.dev); | ||
| 174 | stat->ino = lowerstat.ino; | ||
| 175 | } | ||
| 176 | } else { | ||
| 177 | stat->ino = dentry->d_inode->i_ino; | ||
| 178 | } | ||
| 156 | 179 | ||
| 180 | /* | ||
| 181 | * Always use the overlay st_dev for directories, so 'find -xdev' will | ||
| 182 | * scan the entire overlay mount and won't cross the overlay mount | ||
| 183 | * boundaries. | ||
| 184 | */ | ||
| 157 | stat->dev = dentry->d_sb->s_dev; | 185 | stat->dev = dentry->d_sb->s_dev; |
| 158 | stat->ino = dentry->d_inode->i_ino; | ||
| 159 | 186 | ||
| 160 | /* | 187 | /* |
| 161 | * It's probably not worth it to count subdirs to get the | 188 | * It's probably not worth it to count subdirs to get the |
| @@ -164,8 +191,10 @@ static int ovl_dir_getattr(const struct path *path, struct kstat *stat, | |||
| 164 | */ | 191 | */ |
| 165 | if (OVL_TYPE_MERGE(type)) | 192 | if (OVL_TYPE_MERGE(type)) |
| 166 | stat->nlink = 1; | 193 | stat->nlink = 1; |
| 194 | out: | ||
| 195 | revert_creds(old_cred); | ||
| 167 | 196 | ||
| 168 | return 0; | 197 | return err; |
| 169 | } | 198 | } |
| 170 | 199 | ||
| 171 | /* Common operations required to be done after creation of file on upper */ | 200 | /* Common operations required to be done after creation of file on upper */ |
