Skip to content

Commit 091141a

Browse files
committed
fs: add fget_many() and fput_many()
Some uses cases repeatedly get and put references to the same file, but the only exposed interface is doing these one at the time. As each of these entail an atomic inc or dec on a shared structure, that cost can add up. Add fget_many(), which works just like fget(), except it takes an argument for how many references to get on the file. Ditto fput_many(), which can drop an arbitrary number of references to a file. Reviewed-by: Hannes Reinecke <hare@suse.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent def596e commit 091141a

File tree

4 files changed

+22
-8
lines changed

4 files changed

+22
-8
lines changed

fs/file.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ void do_close_on_exec(struct files_struct *files)
705705
spin_unlock(&files->file_lock);
706706
}
707707

708-
static struct file *__fget(unsigned int fd, fmode_t mask)
708+
static struct file *__fget(unsigned int fd, fmode_t mask, unsigned int refs)
709709
{
710710
struct files_struct *files = current->files;
711711
struct file *file;
@@ -720,23 +720,28 @@ static struct file *__fget(unsigned int fd, fmode_t mask)
720720
*/
721721
if (file->f_mode & mask)
722722
file = NULL;
723-
else if (!get_file_rcu(file))
723+
else if (!get_file_rcu_many(file, refs))
724724
goto loop;
725725
}
726726
rcu_read_unlock();
727727

728728
return file;
729729
}
730730

731+
struct file *fget_many(unsigned int fd, unsigned int refs)
732+
{
733+
return __fget(fd, FMODE_PATH, refs);
734+
}
735+
731736
struct file *fget(unsigned int fd)
732737
{
733-
return __fget(fd, FMODE_PATH);
738+
return __fget(fd, FMODE_PATH, 1);
734739
}
735740
EXPORT_SYMBOL(fget);
736741

737742
struct file *fget_raw(unsigned int fd)
738743
{
739-
return __fget(fd, 0);
744+
return __fget(fd, 0, 1);
740745
}
741746
EXPORT_SYMBOL(fget_raw);
742747

@@ -767,7 +772,7 @@ static unsigned long __fget_light(unsigned int fd, fmode_t mask)
767772
return 0;
768773
return (unsigned long)file;
769774
} else {
770-
file = __fget(fd, mask);
775+
file = __fget(fd, mask, 1);
771776
if (!file)
772777
return 0;
773778
return FDPUT_FPUT | (unsigned long)file;

fs/file_table.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,9 @@ void flush_delayed_fput(void)
326326

327327
static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
328328

329-
void fput(struct file *file)
329+
void fput_many(struct file *file, unsigned int refs)
330330
{
331-
if (atomic_long_dec_and_test(&file->f_count)) {
331+
if (atomic_long_sub_and_test(refs, &file->f_count)) {
332332
struct task_struct *task = current;
333333

334334
if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) {
@@ -347,6 +347,11 @@ void fput(struct file *file)
347347
}
348348
}
349349

350+
void fput(struct file *file)
351+
{
352+
fput_many(file, 1);
353+
}
354+
350355
/*
351356
* synchronous analog of fput(); for kernel threads that might be needed
352357
* in some umount() (and thus can't use flush_delayed_fput() without

include/linux/file.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
struct file;
1414

1515
extern void fput(struct file *);
16+
extern void fput_many(struct file *, unsigned int);
1617

1718
struct file_operations;
1819
struct vfsmount;
@@ -44,6 +45,7 @@ static inline void fdput(struct fd fd)
4445
}
4546

4647
extern struct file *fget(unsigned int fd);
48+
extern struct file *fget_many(unsigned int fd, unsigned int refs);
4749
extern struct file *fget_raw(unsigned int fd);
4850
extern unsigned long __fdget(unsigned int fd);
4951
extern unsigned long __fdget_raw(unsigned int fd);

include/linux/fs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,7 +952,9 @@ static inline struct file *get_file(struct file *f)
952952
atomic_long_inc(&f->f_count);
953953
return f;
954954
}
955-
#define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count)
955+
#define get_file_rcu_many(x, cnt) \
956+
atomic_long_add_unless(&(x)->f_count, (cnt), 0)
957+
#define get_file_rcu(x) get_file_rcu_many((x), 1)
956958
#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
957959
#define file_count(x) atomic_long_read(&(x)->f_count)
958960

0 commit comments

Comments
 (0)