Skip to content

Commit 62d53c4

Browse files
amir73ilbrauner
authored andcommitted
fs: use backing_file container for internal files with "fake" f_path
Overlayfs uses open_with_fake_path() to allocate internal kernel files, with a "fake" path - whose f_path is not on the same fs as f_inode. Allocate a container struct backing_file for those internal files, that is used to hold the "fake" ovl path along with the real path. backing_file_real_path() can be used to access the stored real path. Signed-off-by: Amir Goldstein <[email protected]> Message-Id: <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 8a05a8c commit 62d53c4

File tree

5 files changed

+114
-23
lines changed

5 files changed

+114
-23
lines changed

fs/file_table.c

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,40 @@ static struct kmem_cache *filp_cachep __read_mostly;
4444

4545
static struct percpu_counter nr_files __cacheline_aligned_in_smp;
4646

47+
/* Container for backing file with optional real path */
48+
struct backing_file {
49+
struct file file;
50+
struct path real_path;
51+
};
52+
53+
static inline struct backing_file *backing_file(struct file *f)
54+
{
55+
return container_of(f, struct backing_file, file);
56+
}
57+
58+
struct path *backing_file_real_path(struct file *f)
59+
{
60+
return &backing_file(f)->real_path;
61+
}
62+
EXPORT_SYMBOL_GPL(backing_file_real_path);
63+
4764
static void file_free_rcu(struct rcu_head *head)
4865
{
4966
struct file *f = container_of(head, struct file, f_rcuhead);
5067

5168
put_cred(f->f_cred);
52-
kmem_cache_free(filp_cachep, f);
69+
if (unlikely(f->f_mode & FMODE_BACKING))
70+
kfree(backing_file(f));
71+
else
72+
kmem_cache_free(filp_cachep, f);
5373
}
5474

5575
static inline void file_free(struct file *f)
5676
{
5777
security_file_free(f);
58-
if (!(f->f_mode & FMODE_NOACCOUNT))
78+
if (unlikely(f->f_mode & FMODE_BACKING))
79+
path_put(backing_file_real_path(f));
80+
if (likely(!(f->f_mode & FMODE_NOACCOUNT)))
5981
percpu_counter_dec(&nr_files);
6082
call_rcu(&f->f_rcuhead, file_free_rcu);
6183
}
@@ -226,6 +248,30 @@ struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
226248
return f;
227249
}
228250

251+
/*
252+
* Variant of alloc_empty_file() that allocates a backing_file container
253+
* and doesn't check and modify nr_files.
254+
*
255+
* This is only for kernel internal use, and the allocate file must not be
256+
* installed into file tables or such.
257+
*/
258+
struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
259+
{
260+
struct backing_file *ff;
261+
int error;
262+
263+
ff = kzalloc(sizeof(struct backing_file), GFP_KERNEL);
264+
if (unlikely(!ff))
265+
return ERR_PTR(-ENOMEM);
266+
267+
error = init_file(&ff->file, flags, cred);
268+
if (unlikely(error))
269+
return ERR_PTR(error);
270+
271+
ff->file.f_mode |= FMODE_BACKING | FMODE_NOACCOUNT;
272+
return &ff->file;
273+
}
274+
229275
/**
230276
* alloc_file - allocate and initialize a 'struct file'
231277
*

fs/internal.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
9797
/*
9898
* file_table.c
9999
*/
100-
extern struct file *alloc_empty_file(int, const struct cred *);
101-
extern struct file *alloc_empty_file_noaccount(int, const struct cred *);
100+
struct file *alloc_empty_file(int flags, const struct cred *cred);
101+
struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred);
102+
struct file *alloc_empty_backing_file(int flags, const struct cred *cred);
102103

103104
static inline void put_file_access(struct file *file)
104105
{

fs/open.c

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,23 +1149,44 @@ struct file *kernel_file_open(const struct path *path, int flags,
11491149
}
11501150
EXPORT_SYMBOL_GPL(kernel_file_open);
11511151

1152-
struct file *open_with_fake_path(const struct path *path, int flags,
1153-
struct inode *inode, const struct cred *cred)
1152+
/**
1153+
* backing_file_open - open a backing file for kernel internal use
1154+
* @path: path of the file to open
1155+
* @flags: open flags
1156+
* @path: path of the backing file
1157+
* @cred: credentials for open
1158+
*
1159+
* Open a backing file for a stackable filesystem (e.g., overlayfs).
1160+
* @path may be on the stackable filesystem and backing inode on the
1161+
* underlying filesystem. In this case, we want to be able to return
1162+
* the @real_path of the backing inode. This is done by embedding the
1163+
* returned file into a container structure that also stores the path of
1164+
* the backing inode on the underlying filesystem, which can be
1165+
* retrieved using backing_file_real_path().
1166+
*/
1167+
struct file *backing_file_open(const struct path *path, int flags,
1168+
const struct path *real_path,
1169+
const struct cred *cred)
11541170
{
1155-
struct file *f = alloc_empty_file_noaccount(flags, cred);
1156-
if (!IS_ERR(f)) {
1157-
int error;
1171+
struct file *f;
1172+
int error;
11581173

1159-
f->f_path = *path;
1160-
error = do_dentry_open(f, inode, NULL);
1161-
if (error) {
1162-
fput(f);
1163-
f = ERR_PTR(error);
1164-
}
1174+
f = alloc_empty_backing_file(flags, cred);
1175+
if (IS_ERR(f))
1176+
return f;
1177+
1178+
f->f_path = *path;
1179+
path_get(real_path);
1180+
*backing_file_real_path(f) = *real_path;
1181+
error = do_dentry_open(f, d_inode(real_path->dentry), NULL);
1182+
if (error) {
1183+
fput(f);
1184+
f = ERR_PTR(error);
11651185
}
1186+
11661187
return f;
11671188
}
1168-
EXPORT_SYMBOL(open_with_fake_path);
1189+
EXPORT_SYMBOL_GPL(backing_file_open);
11691190

11701191
#define WILL_CREATE(flags) (flags & (O_CREAT | __O_TMPFILE))
11711192
#define O_PATH_FLAGS (O_DIRECTORY | O_NOFOLLOW | O_PATH | O_CLOEXEC)

fs/overlayfs/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ static struct file *ovl_open_realfile(const struct file *file,
6161
if (!inode_owner_or_capable(real_idmap, realinode))
6262
flags &= ~O_NOATIME;
6363

64-
realfile = open_with_fake_path(&file->f_path, flags, realinode,
65-
current_cred());
64+
realfile = backing_file_open(&file->f_path, flags, realpath,
65+
current_cred());
6666
}
6767
revert_creds(old_cred);
6868

include/linux/fs.h

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
171171
/* File supports non-exclusive O_DIRECT writes from multiple threads */
172172
#define FMODE_DIO_PARALLEL_WRITE ((__force fmode_t)0x1000000)
173173

174+
/* File is embedded in backing_file object */
175+
#define FMODE_BACKING ((__force fmode_t)0x2000000)
176+
174177
/* File was opened by fanotify and shouldn't generate fanotify events */
175178
#define FMODE_NONOTIFY ((__force fmode_t)0x4000000)
176179

@@ -2352,11 +2355,31 @@ static inline struct file *file_open_root_mnt(struct vfsmount *mnt,
23522355
return file_open_root(&(struct path){.mnt = mnt, .dentry = mnt->mnt_root},
23532356
name, flags, mode);
23542357
}
2355-
extern struct file * dentry_open(const struct path *, int, const struct cred *);
2356-
extern struct file *dentry_create(const struct path *path, int flags,
2357-
umode_t mode, const struct cred *cred);
2358-
extern struct file * open_with_fake_path(const struct path *, int,
2359-
struct inode*, const struct cred *);
2358+
struct file *dentry_open(const struct path *path, int flags,
2359+
const struct cred *creds);
2360+
struct file *dentry_create(const struct path *path, int flags, umode_t mode,
2361+
const struct cred *cred);
2362+
struct file *backing_file_open(const struct path *path, int flags,
2363+
const struct path *real_path,
2364+
const struct cred *cred);
2365+
struct path *backing_file_real_path(struct file *f);
2366+
2367+
/*
2368+
* file_real_path - get the path corresponding to f_inode
2369+
*
2370+
* When opening a backing file for a stackable filesystem (e.g.,
2371+
* overlayfs) f_path may be on the stackable filesystem and f_inode on
2372+
* the underlying filesystem. When the path associated with f_inode is
2373+
* needed, this helper should be used instead of accessing f_path
2374+
* directly.
2375+
*/
2376+
static inline const struct path *file_real_path(struct file *f)
2377+
{
2378+
if (unlikely(f->f_mode & FMODE_BACKING))
2379+
return backing_file_real_path(f);
2380+
return &f->f_path;
2381+
}
2382+
23602383
static inline struct file *file_clone_open(struct file *file)
23612384
{
23622385
return dentry_open(&file->f_path, file->f_flags, file->f_cred);

0 commit comments

Comments
 (0)