|
@@ -52,7 +52,8 @@ static void file_free_rcu(struct rcu_head *head)
|
|
static inline void file_free(struct file *f)
|
|
static inline void file_free(struct file *f)
|
|
{
|
|
{
|
|
security_file_free(f);
|
|
security_file_free(f);
|
|
- percpu_counter_dec(&nr_files);
|
|
|
|
|
|
+ if (!(f->f_mode & FMODE_NOACCOUNT))
|
|
|
|
+ percpu_counter_dec(&nr_files);
|
|
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
|
|
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -91,6 +92,34 @@ int proc_nr_files(struct ctl_table *table, int write,
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+static struct file *__alloc_file(int flags, const struct cred *cred)
|
|
|
|
+{
|
|
|
|
+ struct file *f;
|
|
|
|
+ int error;
|
|
|
|
+
|
|
|
|
+ f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL);
|
|
|
|
+ if (unlikely(!f))
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
+
|
|
|
|
+ f->f_cred = get_cred(cred);
|
|
|
|
+ error = security_file_alloc(f);
|
|
|
|
+ if (unlikely(error)) {
|
|
|
|
+ file_free_rcu(&f->f_u.fu_rcuhead);
|
|
|
|
+ return ERR_PTR(error);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ atomic_long_set(&f->f_count, 1);
|
|
|
|
+ rwlock_init(&f->f_owner.lock);
|
|
|
|
+ spin_lock_init(&f->f_lock);
|
|
|
|
+ mutex_init(&f->f_pos_lock);
|
|
|
|
+ eventpoll_init_file(f);
|
|
|
|
+ f->f_flags = flags;
|
|
|
|
+ f->f_mode = OPEN_FMODE(flags);
|
|
|
|
+ /* f->f_version: 0 */
|
|
|
|
+
|
|
|
|
+ return f;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Find an unused file structure and return a pointer to it.
|
|
/* Find an unused file structure and return a pointer to it.
|
|
* Returns an error pointer if some error happend e.g. we over file
|
|
* Returns an error pointer if some error happend e.g. we over file
|
|
* structures limit, run out of memory or operation is not permitted.
|
|
* structures limit, run out of memory or operation is not permitted.
|
|
@@ -105,7 +134,6 @@ struct file *alloc_empty_file(int flags, const struct cred *cred)
|
|
{
|
|
{
|
|
static long old_max;
|
|
static long old_max;
|
|
struct file *f;
|
|
struct file *f;
|
|
- int error;
|
|
|
|
|
|
|
|
/*
|
|
/*
|
|
* Privileged users can go above max_files
|
|
* Privileged users can go above max_files
|
|
@@ -119,26 +147,10 @@ struct file *alloc_empty_file(int flags, const struct cred *cred)
|
|
goto over;
|
|
goto over;
|
|
}
|
|
}
|
|
|
|
|
|
- f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL);
|
|
|
|
- if (unlikely(!f))
|
|
|
|
- return ERR_PTR(-ENOMEM);
|
|
|
|
-
|
|
|
|
- f->f_cred = get_cred(cred);
|
|
|
|
- error = security_file_alloc(f);
|
|
|
|
- if (unlikely(error)) {
|
|
|
|
- file_free_rcu(&f->f_u.fu_rcuhead);
|
|
|
|
- return ERR_PTR(error);
|
|
|
|
- }
|
|
|
|
|
|
+ f = __alloc_file(flags, cred);
|
|
|
|
+ if (!IS_ERR(f))
|
|
|
|
+ percpu_counter_inc(&nr_files);
|
|
|
|
|
|
- atomic_long_set(&f->f_count, 1);
|
|
|
|
- rwlock_init(&f->f_owner.lock);
|
|
|
|
- spin_lock_init(&f->f_lock);
|
|
|
|
- mutex_init(&f->f_pos_lock);
|
|
|
|
- eventpoll_init_file(f);
|
|
|
|
- f->f_flags = flags;
|
|
|
|
- f->f_mode = OPEN_FMODE(flags);
|
|
|
|
- /* f->f_version: 0 */
|
|
|
|
- percpu_counter_inc(&nr_files);
|
|
|
|
return f;
|
|
return f;
|
|
|
|
|
|
over:
|
|
over:
|
|
@@ -150,6 +162,21 @@ over:
|
|
return ERR_PTR(-ENFILE);
|
|
return ERR_PTR(-ENFILE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Variant of alloc_empty_file() that doesn't check and modify nr_files.
|
|
|
|
+ *
|
|
|
|
+ * Should not be used unless there's a very good reason to do so.
|
|
|
|
+ */
|
|
|
|
+struct file *alloc_empty_file_noaccount(int flags, const struct cred *cred)
|
|
|
|
+{
|
|
|
|
+ struct file *f = __alloc_file(flags, cred);
|
|
|
|
+
|
|
|
|
+ if (!IS_ERR(f))
|
|
|
|
+ f->f_mode |= FMODE_NOACCOUNT;
|
|
|
|
+
|
|
|
|
+ return f;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* alloc_file - allocate and initialize a 'struct file'
|
|
* alloc_file - allocate and initialize a 'struct file'
|
|
*
|
|
*
|