@@ -24,6 +24,12 @@ module_param_named(redirect_max, ovl_redirect_max, ushort, 0644);
24
24
MODULE_PARM_DESC (ovl_redirect_max ,
25
25
"Maximum length of absolute redirect xattr value" );
26
26
27
+ static unsignedint ovl_singleton_wt_link_max = 255 ;
28
+ module_param_named (singleton_whiteout_link_max ,
29
+ ovl_singleton_wt_link_max ,uint ,0644 );
30
+ MODULE_PARM_DESC (ovl_singleton_wt_link_max ,
31
+ "Maximum hardlinks of a whiteout singleton" );
32
+
27
33
int ovl_cleanup (struct inode * wdir ,struct dentry * wdentry )
28
34
{
29
35
int err ;
@@ -62,18 +68,149 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir)
62
68
return temp ;
63
69
}
64
70
71
+ #define OVL_SINGLETON_WHITEOUT_NAME "whiteout"
72
+
73
+ /* caller holds write lock (i_rwsem) of dir */
74
+ static int ovl_make_singleton_whiteout_locked (struct ovl_fs * ofs ,
75
+ struct dentry * dir ,const char * name )
76
+ {
77
+ int err = 0 ;
78
+ struct inode * inode = d_inode (dir );
79
+ struct dentry * whiteout ;
80
+
81
+ whiteout = lookup_one_len (name ,dir ,strlen (name ));
82
+ if (IS_ERR (whiteout ))
83
+ return PTR_ERR (whiteout );
84
+
85
+ if (ovl_is_whiteout (whiteout )) {
86
+ ofs -> whiteout = whiteout ;
87
+ }else if (!whiteout -> d_inode ) {
88
+ err = ovl_do_whiteout (inode ,whiteout );
89
+ if (!err )
90
+ ofs -> whiteout = whiteout ;
91
+ else
92
+ dput (whiteout );
93
+ }else {
94
+ /*
95
+ * fallback to creating new whiteout file if
96
+ * a non-whiteout file already exists
97
+ */
98
+ dput (whiteout );
99
+ }
100
+
101
+ return err ;
102
+ }
103
+
104
+ /*
105
+ * create a new whiteout file under workdir if it doesn't exist.
106
+ * If a non-whiteout file already exists, no error will be reported
107
+ * and the needed whiteout file will be newly created instead of
108
+ * being linked to a singleton whiteout.
109
+ */
110
+ int ovl_make_singleton_whiteout (struct ovl_fs * ofs )
111
+ {
112
+ int err ;
113
+ struct inode * dir ;
114
+
115
+ /* disable singleton whiteout */
116
+ if (ovl_singleton_wt_link_max <=1 )
117
+ return 0 ;
118
+
119
+ dir = d_inode (ofs -> workdir );
120
+ inode_lock_nested (dir ,I_MUTEX_PARENT );
121
+
122
+ err = ovl_make_singleton_whiteout_locked (ofs ,ofs -> workdir ,
123
+ OVL_SINGLETON_WHITEOUT_NAME );
124
+
125
+ inode_unlock (dir );
126
+
127
+ return err ;
128
+ }
129
+
130
+ /*
131
+ * caller holds i_mutex of workdir to ensure the operations
132
+ * on the singletion whiteout are serialized.
133
+ */
134
+ static int ovl_link_to_singleton_whiteout (struct ovl_fs * ofs ,
135
+ struct dentry * whiteout ,bool * create_instead )
136
+ {
137
+ int err ;
138
+ struct inode * wdir = d_inode (ofs -> workdir );
139
+ struct dentry * singleton ;
140
+ bool retried = false;
141
+
142
+ * create_instead = false;
143
+ retry :
144
+ singleton = ofs -> whiteout ;
145
+ /* Create a new singletion whiteout when the limit is exceeded */
146
+ if (1 < ovl_singleton_wt_link_max &&
147
+ singleton -> d_inode -> i_nlink >=ovl_singleton_wt_link_max )
148
+ err = - EMLINK ;
149
+ else
150
+ err = ovl_do_link (singleton ,wdir ,whiteout , false);
151
+
152
+ if (!err ) {
153
+ gotoout ;
154
+ }else if (err == - EMLINK && !retried ) {
155
+ /*
156
+ * The singleton already has the maximum number of links to it,
157
+ * so remove the old singleton and create a new one
158
+ */
159
+ ofs -> whiteout = NULL ;
160
+ err = ovl_do_unlink (wdir ,singleton );
161
+ if (err ) {
162
+ dput (singleton );
163
+ gotoout ;
164
+ }
165
+
166
+ dput (singleton );
167
+ err = ovl_make_singleton_whiteout_locked (ofs ,ofs -> workdir ,
168
+ OVL_SINGLETON_WHITEOUT_NAME );
169
+ if (err )
170
+ gotoout ;
171
+
172
+ retried = true;
173
+ if (ofs -> whiteout )
174
+ gotoretry ;
175
+ else
176
+ gotoout_fallback ;
177
+ }else if (err == - EXDEV ) {
178
+ /*
179
+ * upper fs may have a project id different than singleton,
180
+ * so fall back to create whiteout directly
181
+ */
182
+ gotoout_fallback ;
183
+ }else {
184
+ gotoout ;
185
+ }
186
+
187
+ out_fallback :
188
+ * create_instead = true;
189
+ out :
190
+ return err ;
191
+ }
192
+
65
193
/* caller holds i_mutex on workdir */
66
- static struct dentry * ovl_whiteout (struct dentry * workdir )
194
+ static struct dentry * ovl_whiteout (struct ovl_fs * ofs , struct dentry * workdir )
67
195
{
68
196
int err ;
69
197
struct dentry * whiteout ;
70
198
struct inode * wdir = workdir -> d_inode ;
199
+ bool create_instead ;
71
200
72
201
whiteout = ovl_lookup_temp (workdir );
73
202
if (IS_ERR (whiteout ))
74
203
return whiteout ;
75
204
76
- err = ovl_do_whiteout (wdir ,whiteout );
205
+ if (workdir == ofs -> workdir && ofs -> whiteout )
206
+ err = ovl_link_to_singleton_whiteout (ofs ,whiteout ,
207
+ & create_instead );
208
+ else
209
+ create_instead = true;
210
+
211
+ if (create_instead )
212
+ err = ovl_do_whiteout (wdir ,whiteout );
213
+
77
214
if (err ) {
78
215
dput (whiteout );
79
216
whiteout = ERR_PTR (err );
@@ -83,15 +220,15 @@ static struct dentry *ovl_whiteout(struct dentry *workdir)
83
220
}
84
221
85
222
/* Caller must hold i_mutex on both workdir and dir */
86
- int ovl_cleanup_and_whiteout (struct dentry * workdir ,struct inode * dir ,
87
- struct dentry * dentry )
223
+ int ovl_cleanup_and_whiteout (struct ovl_fs * ofs ,struct dentry * workdir ,
224
+ struct inode * dir , struct dentry * dentry )
88
225
{
89
226
struct inode * wdir = workdir -> d_inode ;
90
227
struct dentry * whiteout ;
91
228
int err ;
92
229
int flags = 0 ;
93
230
94
- whiteout = ovl_whiteout (workdir );
231
+ whiteout = ovl_whiteout (ofs , workdir );
95
232
err = PTR_ERR (whiteout );
96
233
if (IS_ERR (whiteout ))
97
234
return err ;
@@ -621,6 +758,7 @@ static bool ovl_matches_upper(struct dentry *dentry, struct dentry *upper)
621
758
static int ovl_remove_and_whiteout (struct dentry * dentry ,
622
759
struct list_head * list )
623
760
{
761
+ struct ovl_fs * ofs = dentry -> d_sb -> s_fs_info ;
624
762
struct dentry * workdir = ovl_workdir (dentry );
625
763
struct dentry * upperdir = ovl_dentry_upper (dentry -> d_parent );
626
764
struct dentry * upper ;
@@ -654,7 +792,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
654
792
gotoout_dput_upper ;
655
793
}
656
794
657
- err = ovl_cleanup_and_whiteout (workdir ,d_inode (upperdir ),upper );
795
+ err = ovl_cleanup_and_whiteout (ofs , workdir ,d_inode (upperdir ),upper );
658
796
if (err )
659
797
gotoout_d_drop ;
660
798