aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/drbd/drbd_debugfs.c58
1 files changed, 54 insertions, 4 deletions
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c
index d393aee37da6..51c64ec7bbc1 100644
--- a/drivers/block/drbd/drbd_debugfs.c
+++ b/drivers/block/drbd/drbd_debugfs.c
@@ -177,8 +177,8 @@ static int in_flight_summary_show(struct seq_file *m, void *pos)
177 connection = first_connection(resource); 177 connection = first_connection(resource);
178 /* This does not happen, actually. 178 /* This does not happen, actually.
179 * But be robust and prepare for future code changes. */ 179 * But be robust and prepare for future code changes. */
180 if (!connection) 180 if (!connection || !kref_get_unless_zero(&connection->kref))
181 return 0; 181 return -ESTALE;
182 182
183 seq_puts(m, "oldest application requests\n"); 183 seq_puts(m, "oldest application requests\n");
184 seq_print_resource_transfer_log_summary(m, resource, connection, jif); 184 seq_print_resource_transfer_log_summary(m, resource, connection, jif);
@@ -187,12 +187,62 @@ static int in_flight_summary_show(struct seq_file *m, void *pos)
187 jif = jiffies - jif; 187 jif = jiffies - jif;
188 if (jif) 188 if (jif)
189 seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif)); 189 seq_printf(m, "generated in %d ms\n", jiffies_to_msecs(jif));
190 kref_put(&connection->kref, drbd_destroy_connection);
190 return 0; 191 return 0;
191} 192}
192 193
194/* simple_positive(file->f_dentry) respectively debugfs_positive(),
195 * but neither is "reachable" from here.
196 * So we have our own inline version of it above. :-( */
197static inline int debugfs_positive(struct dentry *dentry)
198{
199 return dentry->d_inode && !d_unhashed(dentry);
200}
201
202/* make sure at *open* time that the respective object won't go away. */
203static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, void *),
204 void *data, struct kref *kref,
205 void (*release)(struct kref *))
206{
207 struct dentry *parent;
208 int ret = -ESTALE;
209
210 /* Are we still linked,
211 * or has debugfs_remove() already been called? */
212 parent = file->f_dentry->d_parent;
213 /* not sure if this can happen: */
214 if (!parent || !parent->d_inode)
215 goto out;
216 /* serialize with d_delete() */
217 mutex_lock(&parent->d_inode->i_mutex);
218 if (!debugfs_positive(file->f_dentry))
219 goto out_unlock;
220 /* Make sure the object is still alive */
221 if (kref_get_unless_zero(kref))
222 ret = 0;
223out_unlock:
224 mutex_unlock(&parent->d_inode->i_mutex);
225 if (!ret) {
226 ret = single_open(file, show, data);
227 if (ret)
228 kref_put(kref, release);
229 }
230out:
231 return ret;
232}
233
193static int in_flight_summary_open(struct inode *inode, struct file *file) 234static int in_flight_summary_open(struct inode *inode, struct file *file)
194{ 235{
195 return single_open(file, in_flight_summary_show, inode->i_private); 236 struct drbd_resource *resource = inode->i_private;
237 return drbd_single_open(file, in_flight_summary_show, resource,
238 &resource->kref, drbd_destroy_resource);
239}
240
241static int in_flight_summary_release(struct inode *inode, struct file *file)
242{
243 struct drbd_resource *resource = inode->i_private;
244 kref_put(&resource->kref, drbd_destroy_resource);
245 return single_release(inode, file);
196} 246}
197 247
198static const struct file_operations in_flight_summary_fops = { 248static const struct file_operations in_flight_summary_fops = {
@@ -200,7 +250,7 @@ static const struct file_operations in_flight_summary_fops = {
200 .open = in_flight_summary_open, 250 .open = in_flight_summary_open,
201 .read = seq_read, 251 .read = seq_read,
202 .llseek = seq_lseek, 252 .llseek = seq_lseek,
203 .release = single_release, 253 .release = in_flight_summary_release,
204}; 254};
205 255
206void drbd_debugfs_resource_add(struct drbd_resource *resource) 256void drbd_debugfs_resource_add(struct drbd_resource *resource)