]>
git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - fs/aufs/wkq.c
2 * Copyright (C) 2005-2017 Junjiro R. Okajima
4 * This program, aufs is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * workqueue for asynchronous/super-io operations
20 * todo: try new dredential scheme
23 #include <linux/module.h>
26 /* internal workqueue named AUFS_WKQ_NAME */
28 static struct workqueue_struct
*au_wkq
;
31 struct work_struct wk
;
34 unsigned int flags
; /* see wkq.h */
39 struct completion
*comp
;
42 /* ---------------------------------------------------------------------- */
44 static void wkq_func(struct work_struct
*wk
)
46 struct au_wkinfo
*wkinfo
= container_of(wk
, struct au_wkinfo
, wk
);
48 AuDebugOn(!uid_eq(current_fsuid(), GLOBAL_ROOT_UID
));
49 AuDebugOn(rlimit(RLIMIT_FSIZE
) != RLIM_INFINITY
);
51 wkinfo
->func(wkinfo
->args
);
52 if (au_ftest_wkq(wkinfo
->flags
, WAIT
))
53 complete(wkinfo
->comp
);
55 kobject_put(wkinfo
->kobj
);
56 module_put(THIS_MODULE
); /* todo: ?? */
62 * Since struct completion is large, try allocating it dynamically.
64 #if 1 /* defined(CONFIG_4KSTACKS) || defined(AuTest4KSTACKS) */
65 #define AuWkqCompDeclare(name) struct completion *comp = NULL
67 static int au_wkq_comp_alloc(struct au_wkinfo
*wkinfo
, struct completion
**comp
)
69 *comp
= kmalloc(sizeof(**comp
), GFP_NOFS
);
71 init_completion(*comp
);
78 static void au_wkq_comp_free(struct completion
*comp
)
86 #define AuWkqCompDeclare(name) \
87 DECLARE_COMPLETION_ONSTACK(_ ## name); \
88 struct completion *comp = &_ ## name
90 static int au_wkq_comp_alloc(struct au_wkinfo
*wkinfo
, struct completion
**comp
)
96 static void au_wkq_comp_free(struct completion
*comp __maybe_unused
)
100 #endif /* 4KSTACKS */
102 static void au_wkq_run(struct au_wkinfo
*wkinfo
)
104 if (au_ftest_wkq(wkinfo
->flags
, NEST
)) {
106 AuWarn1("wkq from wkq, unless silly-rename on NFS,"
107 " due to a dead dir by UDBA?\n");
108 AuDebugOn(au_ftest_wkq(wkinfo
->flags
, WAIT
));
111 au_dbg_verify_kthread();
113 if (au_ftest_wkq(wkinfo
->flags
, WAIT
)) {
114 INIT_WORK_ONSTACK(&wkinfo
->wk
, wkq_func
);
115 queue_work(au_wkq
, &wkinfo
->wk
);
117 INIT_WORK(&wkinfo
->wk
, wkq_func
);
118 schedule_work(&wkinfo
->wk
);
123 * Be careful. It is easy to make deadlock happen.
124 * processA: lock, wkq and wait
125 * processB: wkq and wait, lock in wkq
128 int au_wkq_do_wait(unsigned int flags
, au_wkq_func_t func
, void *args
)
131 AuWkqCompDeclare(comp
);
132 struct au_wkinfo wkinfo
= {
138 err
= au_wkq_comp_alloc(&wkinfo
, &comp
);
141 /* no timeout, no interrupt */
142 wait_for_completion(wkinfo
.comp
);
143 au_wkq_comp_free(comp
);
144 destroy_work_on_stack(&wkinfo
.wk
);
152 * Note: dget/dput() in func for aufs dentries are not supported. It will be a
153 * problem in a concurrent umounting.
155 int au_wkq_nowait(au_wkq_func_t func
, void *args
, struct super_block
*sb
,
159 struct au_wkinfo
*wkinfo
;
161 atomic_inc(&au_sbi(sb
)->si_nowait
.nw_len
);
164 * wkq_func() must free this wkinfo.
165 * it highly depends upon the implementation of workqueue.
168 wkinfo
= kmalloc(sizeof(*wkinfo
), GFP_NOFS
);
170 wkinfo
->kobj
= &au_sbi(sb
)->si_kobj
;
171 wkinfo
->flags
= flags
& ~AuWkq_WAIT
;
175 kobject_get(wkinfo
->kobj
);
176 __module_get(THIS_MODULE
); /* todo: ?? */
181 au_nwt_done(&au_sbi(sb
)->si_nowait
);
187 /* ---------------------------------------------------------------------- */
189 void au_nwt_init(struct au_nowait_tasks
*nwt
)
191 atomic_set(&nwt
->nw_len
, 0);
192 /* smp_mb(); */ /* atomic_set */
193 init_waitqueue_head(&nwt
->nw_wq
);
196 void au_wkq_fin(void)
198 destroy_workqueue(au_wkq
);
201 int __init
au_wkq_init(void)
206 au_wkq
= alloc_workqueue(AUFS_WKQ_NAME
, 0, WQ_DFL_ACTIVE
);
208 err
= PTR_ERR(au_wkq
);